Todo:

ghg_emissions_clean <- read_csv("data/clean_data/ghg_emissions_summary.csv")

-- Column specification ---------------------------------------------------------------------------------------
cols(
  ccp_mapping = col_character(),
  pollutant = col_character(),
  year = col_double(),
  value = col_double(),
  units = col_character()
)


summarised <- group_and_summarise_exclude(ghg_emissions_clean, c("year", "value", "units"))


summarised %>% 
  ggplot() +
  aes(x = .data[["ccp_mapping"]], y = value, fill = .data[["ccp_mapping"]]) +
  geom_col()

new_ulevs %>% 
  filter(!statistic == "Proportion of New Vehicle Registrations that are ULEV") %>% 
  # write_csv("data/clean_data/transport/newly_registered_vehicles_and_ulevs.csv")
  group_by(year, statistic) %>%
  summarise(value = sum(value, na.rm = TRUE), .groups = 'drop_last') %>% 
  summarise(value = lag(value)/value, .groups = 'drop_last') %>% 
  drop_na() %>% 
  ggplot() +
  aes(x = year, y = value) +
  geom_line() +
  geom_point()

base_var = "year"
base_value = 2018
base_modifier = 0.8


road_traffic %>% 
  filter(vehicle_type == "Cars") %>% 
  group_by(year) %>% 
  summarise(value = sum(value, na.rm = TRUE), .groups = 'drop_last') %>%
  ggplot() +
  aes(x = year, y = value) +
  geom_line() +
  geom_point() +
  geom_point(aes(x = 2030, y = (.data[["value"]][.data[[base_var]] == base_value])*base_modifier),
             colour = "darkgreen", shape = 13, size = 5) +
  ylim(0, NA)

road_traffic %>% 
  filter(.data[["year"]] == 2018,
         .data[["vehicle_type"]] == "Cars") %>%
  summarise(value = sum(.data[["value"]]))
sales <- data.frame(
  year = c(2005, 2006, 2007, 2008),
  profit = c(340, 500, 600, 550)
)

sales %>% 
  ggplot() +
  aes(x = year, y = profit) +
  geom_line() +
  geom_point(aes(x = 2010, y = (.data[['profit']][.data[["year"]] == 2008]*1.1)))


pull(sales[sales[["year"]] == 2008, ]["profit"])*1.1
[1] 605
remove <- c("year", "value", "units")
temp <- names(ghg_emissions_clean)

remaining_cols <- temp [!temp %in% remove]

ghg_emissions_clean %>%
  dplyr::group_by_at(remaining_cols) %>% 
  summarise(value = sum(value, na.rm = TRUE), .groups = 'drop_last') %>% 
  
summarised_data <- emissions_data %>% 
  group_and_summarise(ccp_mapping, pollutant)
create_bar_plot <-function(df = summarised_data) {
  x_name <- names(df)[1]
  
  df %>% 
  ggplot() +
    aes(x = x_name, y = value, fill = x_name) +
    geom_col(position = "stack", show.legend = FALSE)
}
test_function <- function(df, var) {
  # convert snakecase variable name to title for ui
  varname <- str_to_title(str_replace_all(var, "_", " "))
  
}
build_slider_input <- function(df, varname) {
  rng <- range(df, na.rm = TRUE)
  
  sliderInput(var,
              paste0(varname, " Range:"),
              min = rng[1],
              max = rng[2],
              value = rng,
              sep = "",
              step = 1,
              ticks = FALSE)
}
  
test_function(df = emissions_data, var = "pollutant")
[1] "pickerInput"
substr("jewel", 2, nchar("jewel"))
[1] "ewel"
test <- "ccp_mapping\",\"pollutant"

eval(parse(text=gsub("\\", "", deparse(test), fixed=TRUE)))
Error in parse(text = gsub("\\", "", deparse(test), fixed = TRUE)) : 
  <text>:1:14: unexpected ','
1: "ccp_mapping",
                 ^
test_function <- function(df, var) {
  # convert snakecase variable name to title for ui
  varname <- str_to_title(str_replace_all(var, "_", " "))
  
  print(dropdown_lookup[[var]])
}
  
emissions_data %>% 
  group_by_("ccp_mapping", "pollutant") %>% 
  summarise(value = sum(value, na.rm = TRUE))
`summarise()` regrouping output by 'ccp_mapping' (override with `.groups` argument)
emissions_data %>% 
  group_by(ccp_mapping, pollutant) %>% 
  summarise(value = sum(value, na.rm = TRUE), .groups = 'drop_last') %>% 
  ggplot() +
  aes(x = names(emissions_data)[1], y = value) +
  geom_col()

emissions_data <- read_csv("data/clean_data/ghg_emissions.csv")

-- Column specification ------------------------------------------------------------------------------------------------------------------------
cols(
  ccp_mapping = col_character(),
  source_name = col_character(),
  pollutant = col_character(),
  year = col_double(),
  value = col_double(),
  units = col_character()
)
emissions_data %>%
  group_by(year) %>% 
  summarise(value = sum(value, na.rm = TRUE)) %>% 
  ggplot() +
    aes(x = year,
        y = value) +
  geom_line() +
  ylim(0, NA)
`summarise()` ungrouping output (override with `.groups` argument)

Only emissions - > emissions that are greater than 0

ghg_true_emissions <- ghg_emissions_clean %>% 
  filter(year == max(ghg_emissions_clean$year)) %>% 
  filter(value >= 0) %>% 
  mutate(across(where(is.character), ~str_to_title(.)))
# need to split by pollutant and year
ghg_emissions_clean %>% 
  select(ccp_mapping, source_name) %>% 
  filter(str_detect(source_name, paste("^", ccp_mapping, sep = ""))) %>% 
  unique()
ghg_wide_emissions <- ghg_wide %>%
  filter(!value < 0)

ghg_wide_sinks <- ghg_wide %>% 
  filter(value < 0)

get_child_cols <- function(df, additional_vars, standard_vars = c("value", "units")) {
  temp <- names(df)
  remove <- c(additional_vars, standard_vars)
  
  child_cols <- temp [!temp %in% remove]
}


child_cols <- get_child_cols(ghg_wide_emissions, additional_vars)

child_cols
[1] "child_order_0" "child_order_1" "child_order_2" "child_order_3"
previous_children
NULL
create_child_table(ghg_wide_emissions,
                   current_child = "child_order_0",
                   previous_children = NULL,
                   additional_vars = c("pollutant", "year"))
Error: Problem with `mutate()` input `..1`.
x Input `..1` must be a vector, not a `quosure/formula` object.
i Input `..1` is `current_child`.
Run `rlang::last_error()` to see where the error occurred.
previous_children <- NULL

children <- c(previous_children, "child_order_0")

children
[1] "child_order_0"
road_traffic <- read_csv("data/clean_data/transport/road_traffic.csv")

-- Column specification -----------------------------------------------------------------------------------------------------------------------
cols(
  road_type = col_character(),
  vehicle_type = col_character(),
  year = col_double(),
  value = col_double(),
  units = col_character()
)


road_traffic %>% 
  filter(road_type == "Major roads (M and A)") %>%
  filter(!str_detect(vehicle_type, "^All")) %>% 
  filter(year == 2018) %>% 
  ggplot() +
  aes(x = .data[["vehicle_type"]], y = value, fill = .data[["vehicle_type"]]) +
  geom_col() +
  ylim(0, NA)

create_child_table <- function(df, current_child, previous_children, additional_vars) {
  current_child <- quo(current_child)
  previous_children <- quo(previous_children)
  additional_vars <- quo(additional_vars)
  
  df %>% 
    group_by(!!current_child, rev(!!previous_children), !!additional_vars) %>% 
    summarise(value = sum(value), .groups = 'drop') %>% 
    unite(!!previous_children, col = "parent", sep = " - ") %>% 
    unite(c(!!previous_children, !!current_child), sep = " - ") %>% 
    select(id, label = !!current_child, parent, !!additional_vars, value)
}
names(ghg_wide_emissions) %in% "child_order_[0-9]"
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
  
temp <- names(ghg_wide_emissions)
remove <- c(additional_vars, "value", "units")


temp [!temp %in% remove]
[1] "child_order_0" "child_order_1" "child_order_2" "child_order_3"

TODO::

dashboard - review page dashboard - transport explorer

create_child_table(ghg_wide_emissions, current_child = "child_order_0",
                   previous_children = "", additional_vars = c("pollutant", "year"))
Error: Invalid index: out of bounds
create_child_table(ghg_wide_emissions, current_child = child_order_0,
                   previous_children = NULL, additional_vars = c(pollutant, year))
Error: Problem with `mutate()` input `..1`.
x Input `..1` must be a vector, not a `quosure/formula` object.
i Input `..1` is `current_child`.
Run `rlang::last_error()` to see where the error occurred.
if (is.null(previous_children)) {
  print("bean")
}
[1] "bean"
vector <- c("child_1", "child_2")

paste(paste(vector, collapse = " - "),"child_3", sep = " - ")
[1] "child_1 - child_2 - child_3"

df %>% group_by(current_child, rev(previous_children), additional_vars) %>% summarise(value = sum(value), .groups = “drop”) %>% mutate(id = paste(previous_children, current_child, sep = " - “), parent = paste(previous_children, sep =” - ")) %>% select(id, label = current_child, parent, additional_vars, value)

vector <- c()

paste(paste(vector, sep = " - "),"child_3", sep = " - ")
[1] " - child_3"
vector <- c()

tibble(
  parent = c("bean", "curd", "whey", "sprout", ""),
  people = c("david", "sasha", "john", "smith", "delilah"),
  shapes = c("triangle", "rectangle", "square", "diamond", "")
) %>% 
  unite(c(1,2,3), col = "id", sep = " - ", remove = FALSE)
tibble(
  parent = c("dad", "bean", "", "fava"),
  child = c("")
) %>% 
  select(child) %>% 
  pull()
[1] "" "" "" ""
# get sector totals for parent df (top level)

ghg_sector_totals <- ghg_true_emissions %>% 
  group_by(ccp_mapping) %>% 
  summarise(sector_total = sum(value), .groups = "drop_last")

parent_df <- ghg_sector_totals %>% 
  mutate(parent = "") %>% 
  select(label = ccp_mapping,
         parent,
         value = sector_total)

# the rest of the data

children_df <- ghg_true_emissions %>% 
  filter(year == max(ghg_true_emissions$year)) %>% 
  group_by(source_name, ccp_mapping) %>% 
  summarise(value = sum(value), .groups = "drop_last") %>% 
  select(label = source_name,
         parent = ccp_mapping,
         value)

# combine into one hierarchical df, create id column

emissions_long <- bind_rows(list(parent_df, children_df)) %>% 
  mutate(id = paste(parent, label, sep = " - "), .before = 'label') %>% 
  mutate(id = str_remove(id, "^ - "))

Other method - seperate column

parents <- emissions_wide %>% 
  filter(is.na(second)) %>% 
  select(id, label, parent, value)
first_born <- emissions_wide %>% 
  filter(!is.na(second)) %>% 
  group_by(second, first) %>% 
  summarise(value = sum(value), .groups = "drop_last") %>% 
  mutate(id = paste(first, second, sep = " - ")) %>% 
  ungroup() %>% 
  select(id,
         label = second,
         parent = first,
         value)
second_born <- emissions_wide %>% 
  filter(!is.na(third)) %>% 
  group_by(third, second, first) %>% 
  summarise(value = sum(value), .groups = "drop_last") %>% 
  mutate(id = paste(first, second, third, sep = " - ")) %>% 
  mutate(parent = paste(first, second, sep = " - ")) %>% 
  ungroup() %>% 
  select(id,
         label = third,
         parent,
         value)
third_born <- emissions_wide %>% 
  filter(!is.na(fourth)) %>% 
  group_by(fourth, third, second, first) %>% 
  summarise(value = sum(value), .groups = "drop_last") %>% 
  mutate(id = paste(first, second, third, fourth, sep = " - ")) %>% 
  mutate(parent = paste(first, second, third, sep = " - ")) %>% 
  ungroup() %>% 
  select(id,
         label = fourth,
         parent,
         value)
n_potential_child_layers <- emissions_long %>% 
  select(id) %>% 
  pull() %>% 
  str_count(" - ") %>% 
  max()
# the number of potential child layers is the maximum included in the dataset
n_potential_child_layers <- emissions_long %>% 
  select(id) %>% 
  pull() %>% 
  str_count(" - ") %>% 
  max()
create_hierarchy_df <- function(df, id_col = "id", id_sep = " - ") {
  n_potential_child_layers <- df %>% 
    select(col) %>% 
    pull() %>% 
    str_count(sep) %>% 
    max()
  
  
}
fig <- plot_ly()

fig <- fig %>%
  add_trace(
    name = "Emissions",
    ids = emissions$id,
    labels = emissions$label,
    parents = emissions$parent,
    values = emissions$value,
    text = emissions$units,
    type = 'sunburst',
    maxdepth = 2,
    domain = list(column = 0),
    branchvalues = 'total',
    insidetextorientation = 'radial',
    marker=list(colorscale='Viridis'),
    text = ~units,
    textinfo='label+percent root+value',
    hoverinfo = paste("%{label}: <br>%{value}",'text')
    ) 
fig <- fig %>%
  add_trace(
    name = "Sinks",
    ids = sinks$id,
    labels = sinks$label,
    parents = sinks$parent,
    values = sinks$value,
    text = sinks$units,
    type = 'sunburst',
    maxdepth = 2,
    domain = list(column = 1),
    branchvalues = 'total',
    insidetextorientation = 'radial',
    marker=list(colorscale='Viridis'),
    text = ~units,
    textinfo='label+percent root+value',
    hoverinfo = paste("%{label}: <br>%{value}",'text')
  ) 
fig <- fig %>%
    layout(
      grid = list(columns =2, rows = 1),
      margin = list(l = 0, r = 0, b = 0, t = 0))

fig
tibble(
  labels = c("Eve", "Seth", "Enos", "Noam", "Awan", "Enoch"),
  parents = c("", "Eve", "Seth", "Seth", "Eve", "Awan"),
  values = c(16, 12, 10, 2, 4, 4)
)
fig <- plot_ly(
  labels = cain_ble$labels,
  parents = cain_ble$parents,
  values = cain_ble$values,
  type = 'sunburst'
)

fig
emissions_long$label[1:10]
 [1] "Agriculture"            "Electricity Generation" "Industry"               "Land use"               "Residential"           
 [6] "Services"               "Transport"              "Waste"                  "Accidental fires"       "Accidental fires"      
d <- data.frame(
    ids = c(
    "North America", "Europe", "Australia", "North America - Football", "Soccer",
    "North America - Rugby", "Europe - Football", "Rugby",
    "Europe - American Football","Australia - Football", "Association",
    "Australian Rules", "Autstralia - American Football", "Australia - Rugby",
    "Rugby League", "Rugby Union"
  ),
  labels = c(
    "North<br>America", "Europe", "Australia", "Football", "Soccer", "Rugby",
    "Football", "Rugby", "American<br>Football", "Football", "Association",
    "Australian<br>Rules", "American<br>Football", "Rugby", "Rugby<br>League",
    "Rugby<br>Union"
  ),
  parents = c(
    "", "", "", "North America", "North America", "North America", "Europe",
    "Europe", "Europe","Australia", "Australia - Football", "Australia - Football",
    "Australia - Football", "Australia - Football", "Australia - Rugby",
    "Australia - Rugby"
  ),
  stringsAsFactors = FALSE
)

fig <- plot_ly(d, ids = ~ids, labels = ~labels, parents = ~parents, type = 'sunburst')

d
class(emissions_long)
[1] "tbl_df"     "tbl"        "data.frame"
class(cain_ble)
[1] "tbl_df"     "tbl"        "data.frame"
class(cain_ble)
diff_order <- ghg_emissions_clean %>% 
  dplyr::group_by(ccp_mapping, year, pollutant) %>% 
  dplyr::summarise(value = sum(value), units = units[1], .groups = "keep") %>%
  filter(pollutant == "CO2") %>% 
  filter(year == min(ghg_emissions_clean$year) |
           year == max(ghg_emissions_clean$year)) %>% 
  ungroup() %>% 
  group_by(ccp_mapping) %>% 
  mutate(diff = lag(value) - value) %>% 
  arrange(diff) %>%
  drop_na() %>% 
  select(ccp_mapping) %>% 
  pull()
ghg_emissions_clean %>% 
  dplyr::group_by(ccp_mapping, year, pollutant) %>% 
  dplyr::summarise(value = sum(value), units = units[1], .groups = "keep") %>%
  filter(pollutant == "CO2") %>%
  mutate(ccp_mapping = factor(ccp_mapping, levels = rev(diff_order))) %>% 
  ggplot() +
  aes(x = year, y = value, fill = ccp_mapping) +
  geom_area() +
  facet_wrap(~pollutant) +
  theme_bw()
ghg_emissions_clean %>% 
  group_by(pollutant) %>% 
  summarise(emissions = sum(value))
plotly::ggplotly(
  ghg_emissions_clean %>% 
    filter(year == 2018) %>%
    filter(pollutant %in% c("CO2", "CH4")) %>%
    ggplot() +
    aes(x = factor(ccp_mapping, levels = rev(levels(factor(ccp_mapping)))),
        y = value, fill = source_name,
        text = paste0('</br> Sector: ', ccp_mapping,
                      '</br> Emissions: ', value,
                      '</br> Source Name: ', source_name)) +
    geom_col(position = "stack") +
    theme_bw() +
    theme(legend.position = "none") +
    labs(x = "Sector",
         y = paste0("Emissions (", ghg_emissions_clean$units[1], ")")) +
    coord_flip(),
    tooltip = 'text'
  )
ghg_emissions_data %>% 
  names()
ghg_emissions_data %>% 
  select()
input <- list()

input$col_choice = "national_communication_categories"
ghg_emissions_clean %>%
  group_by_(input$col_choice, "emission_year") %>% 
  summarise(total_ghg_emissions = sum(emissions)) %>% 
  ggplot() +
  aes(x = EmissionYear, y = total_ghg_emissions, group = `National Communication Categories`, colour = `National Communication Categories`) +
  geom_line() +
  geom_point() +
  scale_x_continuous(breaks = seq(1990,2020,5)) +
  theme(legend.position = 0)
ghg_emissions_data %>% 
  distinct(`National Communication Categories`)
ghg_emissions_data %>% 
  filter(EmissionYear != "BaseYear") %>% 
  mutate(EmissionYear = as.numeric(EmissionYear)) %>% 
  group_by(EmissionYear) %>% 
  summarise(total_ghg_emissions = sum(`Emissions (MtCO2e)`)) %>% 
  ggplot() +
  aes(x = EmissionYear, y = total_ghg_emissions) +
  geom_line() +
  geom_point() +
  scale_x_continuous(breaks = seq(1990,2020,5)) +
  ylim(0, 80) +
  theme(legend.position = 0) +
  theme_bw()
ghg_emissions_data %>% 
  distinct(`CCP mapping`)
ghg_emissions_data %>% 
  filter(EmissionYear != "BaseYear") %>% 
  mutate(EmissionYear = as.numeric(EmissionYear)) %>% 
  group_by(`CCP mapping`, EmissionYear) %>% 
  summarise(total_ghg_emissions = sum(`Emissions (MtCO2e)`)) %>% 
  ggplot() +
  aes(x = EmissionYear, y = total_ghg_emissions, group = `CCP mapping`, colour = `CCP mapping`) +
  geom_line() +
  geom_point() +
  scale_x_continuous(breaks = seq(1990,2020,5))
`summarise()` regrouping output by 'CCP mapping' (override with `.groups` argument)

ghg_emissions_data %>% 
  filter(EmissionYear != "BaseYear") %>% 
  mutate(EmissionYear = as.numeric(EmissionYear)) %>% 
  filter(`National Communication Categories` != `CCP mapping`) %>% 
  select(`National Communication Categories`, `CCP mapping`) %>% 
  unique()
emissions_sankey <- emissions_data %>% 
  select(ccp_mapping, source_name, pollutant, emission_year, emissions, units)

category_id,category_name,subcategory_id,subcategory_name,year,emissions,emission

filtered_df <- ghg_emissions_clean %>% 
  select(ccp_mapping, source_name, pollutant, emission_year, emissions, units) %>% 
  filter(pollutant == "CO2") %>% 
  filter(emission_year == "2005")
total_emissions_for_gas <- filtered_df %>% 
  summarise(sum(emissions)) %>% 
  pull()

total_emissions_by_category <- filtered_df %>% 
  select(-pollutant) %>% 
  group_by(ccp_mapping) %>% 
  summarise(cat_sum = sum(emissions), .groups = 'drop_last')
categories <- filtered_df %>% 
  distinct(ccp_mapping) %>% 
  pull()

n_categories <- length(categories)

sources <- filtered_df %>% 
  distinct(source_name) %>% 
  pull()

n_sources <- length(sources)
n_sources
[1] 159
node_names <- c("Total", categories, sources, "Other")

node_names_df <- data.frame("name" = node_names)

total_sankey_tibble <- total_emissions_by_category %>%
  mutate(total = "Total") %>% 
  mutate(total = match(total, node_names) -1) %>% 
  mutate(ccp_mapping = match(ccp_mapping, node_names) -1) %>% 
  select(source = total,
         target = ccp_mapping,
         value = cat_sum)

total_filtered_emissions <- total_sankey_tibble %>% 
  summarise(sum(value)) %>% 
  pull()

other_emissions <- total_emissions_for_gas - total_filtered_emissions

total_other_sankey_tibble <- tibble(
  "source" = c(0),
  "target" = (match("Other", node_names) -1),
  "value" = c(other_emissions)
)


sub_sankey_tibble <- filtered_df %>% 
  select(- c(units, pollutant, emission_year)) %>% 
  mutate(ccp_mapping = match(ccp_mapping, node_names) -1,
         source_name = match(source_name, node_names) -1)

names(sub_sankey_tibble) = c("source", "target", "value")

sankey_tibble <- total_sankey_tibble %>% 
  bind_rows(sub_sankey_tibble) %>% 
  bind_rows(total_other_sankey_tibble)

links_matrix <- data.frame(as.matrix(sankey_tibble, byrow = TRUE, ncols = 3))

# Add a 'group' column to each connection:
links <- links_matrix %>% 
  mutate(group = case_when(
    source == 0 ~ paste("type_", target, sep = ""),
    source!=0 ~ paste("type_", source, sep = "")
  ))

nodes <- node_names_df
# Add a 'group' column to each node.
# All of them in the same group to make them the same colour
nodes$group <- as.factor(c("my_unique_group"))

emissions <- list()

emissions$nodes <- nodes
emissions$links <- links
node_names <- c("Total", categories, sources, "Other")

node_names_df <- data.frame("name" = node_names)

total_sankey_tibble <- total_emissions_by_category %>%
  mutate(total = "Total") %>% 
  mutate(total = match(total, node_names) -1) %>% 
  mutate(ccp_mapping = match(ccp_mapping, node_names) -1) %>% 
  select(source = total,
         target = ccp_mapping,
         value = cat_sum)

total_filtered_emissions <- total_sankey_tibble %>% 
  summarise(sum(value)) %>% 
  pull()

other_emissions <- total_emissions_for_gas - total_filtered_emissions

total_other_sankey_tibble <- tibble(
  "source" = c(0),
  "target" = (match("Other", node_names) -1),
  "value" = c(other_emissions)
)


sub_sankey_tibble <- filtered_df %>% 
  select(- c(units, pollutant, emission_year)) %>% 
  mutate(ccp_mapping = match(ccp_mapping, node_names) -1,
         source_name = match(source_name, node_names) -1)

names(sub_sankey_tibble) = c("source", "target", "value")

sankey_tibble <- total_sankey_tibble %>% 
  bind_rows(sub_sankey_tibble) %>% 
  bind_rows(total_other_sankey_tibble)

links_matrix <- data.frame(as.matrix(sankey_tibble, byrow = TRUE, ncols = 3))

# Add a 'group' column to each connection:
links <- links_matrix %>% 
  mutate(group = case_when(
    source == 0 ~ paste("type_", target, sep = ""),
    source!=0 ~ paste("type_", source, sep = "")
  ))

nodes <- node_names_df
# Add a 'group' column to each node.
# All of them in the same group to make them the same colour
nodes$group <- as.factor(c("my_unique_group"))

emissions <- list()

emissions$nodes <- nodes
emissions$links <- links
total_filtered_emissions <- total_sankey_tibble %>% 
  summarise(sum(value)) %>% 
  pull()

other_emissions <- total_emissions_for_gas - total_filtered_emissions

total_other_sankey_tibble <- tibble(
  "source" = c(0),
  "target" = (match("Other", node_names) -1),
  "value" = c(other_emissions)
)

sub_sankey_tibble <- filtered_tibble %>% 
  select(-category_id, -subcategory_id, -year) %>% 
  mutate(category_name = match(category_name, node_names) -1,
         subcategory_name = match(subcategory_name, node_names) -1)

names(sub_sankey_tibble) = c("source", "target", "value")

sankey_tibble <- total_sankey_tibble %>% 
  bind_rows(sub_sankey_tibble) %>% 
  bind_rows(total_other_sankey_tibble)

links_matrix <- data.frame(as.matrix(sankey_tibble, byrow = TRUE, ncols = 3))

# Add a 'group' column to each connection:
links <- links_matrix %>% 
  mutate(group = case_when(
    source == 0 ~ paste("type_", target, sep = ""),
    source!=0 ~ paste("type_", source, sep = "")
  ))

nodes <- node_names_df
# Add a 'group' column to each node.
# All of them in the same group to make them the same colour
nodes$group <- as.factor(c("my_unique_group"))

emissions <- list()

emissions$nodes <- nodes
emissions$links <- links
make_sankey_dfs <- function(data, userYear, userGas) {
  n_categories <- data %>% 
    distinct(category_name) %>% 
    nrow()
  
  total_emissions_for_gas <- data %>% 
    filter(emission == userGas()) %>% 
    filter(year == userYear()) %>%
    summarise(sum(emissions)) %>% 
    pull()
  
  filtered_tibble <- data %>%
    filter(emission == userGas()) %>% 
    select(-emission) %>% 
    filter(year == userYear()) %>% 
    filter(emissions > userResolution())
  
  total_emissions_by_cat <- filtered_tibble %>%
    group_by(category_name) %>% 
    summarise(cat_sum = sum(emissions), .groups = 'drop_last')
  
  categories <- filtered_tibble %>%
    distinct(category_name) %>% 
    pull()
  
  subcategories <- filtered_tibble %>%
    distinct(subcategory_name) %>% 
    pull()
  
  node_names <- c("Total", categories, subcategories, "Other")
  
  node_names_df <- data.frame("name" = node_names)
  
  total_sankey_tibble <- total_emissions_by_cat %>%
    mutate(total = "Total") %>% 
    mutate(total = match(total, node_names) -1) %>% 
    mutate(category_name = match(category_name, node_names) -1) %>% 
    select(source = total,
           target = category_name,
           value = cat_sum)
  
  total_filtered_emissions <- total_sankey_tibble %>% 
    summarise(sum(value)) %>% 
    pull()
  
  other_emissions <- total_emissions_for_gas - total_filtered_emissions
  
  total_other_sankey_tibble <- tibble(
    "source" = c(0),
    "target" = (match("Other", node_names) -1),
    "value" = c(other_emissions)
  )
  
  sub_sankey_tibble <- filtered_tibble %>% 
    select(-category_id, -subcategory_id, -year) %>% 
    mutate(category_name = match(category_name, node_names) -1,
           subcategory_name = match(subcategory_name, node_names) -1)
  
  names(sub_sankey_tibble) = c("source", "target", "value")
  
  sankey_tibble <- total_sankey_tibble %>% 
    bind_rows(sub_sankey_tibble) %>% 
    bind_rows(total_other_sankey_tibble)
  
  links_matrix <- data.frame(as.matrix(sankey_tibble, byrow = TRUE, ncols = 3))
  
  # Add a 'group' column to each connection:
  links <- links_matrix %>% 
    mutate(group = case_when(
      source == 0 ~ paste("type_", target, sep = ""),
      source!=0 ~ paste("type_", source, sep = "")
    ))
  
  nodes <- node_names_df
  # Add a 'group' column to each node.
  # All of them in the same group to make them the same colour
  nodes$group <- as.factor(c("my_unique_group"))
  
  emissions <- list()
  
  emissions$nodes <- nodes
  emissions$links <- links
  
  return(emissions)
}
make_sankey_dfs(emissions_sankey, userYear = 2005, userGas = "CH4", userResolution = 50)
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KIyBUb2RvOg0KDQotIGFkZCBjb2x1bW5zIGZvciB0b3RhbHMgZm9yIGVhY2ggcG9sbHV0YW50L3NlY3Rvcg0KDQpgYGB7cn0NCiMgbG9hZCBsaWJyYXJpZXMgYW5kIHJlYWQgZGF0YQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkocGxvdGx5KQ0KDQpnaGdfZW1pc3Npb25zX2NsZWFuIDwtIHJlYWRfY3N2KCJkYXRhL2NsZWFuX2RhdGEvZ2hnX2VtaXNzaW9uc19zdW1tYXJ5LmNzdiIpDQpgYGANCg0KYGBge3J9DQoNCg0Kc3VtbWFyaXNlZCA8LSBncm91cF9hbmRfc3VtbWFyaXNlX2V4Y2x1ZGUoZ2hnX2VtaXNzaW9uc19jbGVhbiwgYygieWVhciIsICJ2YWx1ZSIsICJ1bml0cyIpKQ0KDQoNCnN1bW1hcmlzZWQgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGFlcyh4ID0gLmRhdGFbWyJjY3BfbWFwcGluZyJdXSwgeSA9IHZhbHVlLCBmaWxsID0gLmRhdGFbWyJjY3BfbWFwcGluZyJdXSkgKw0KICBnZW9tX2NvbCgpDQpgYGANCg0KDQpgYGB7cn0NCm5ld191bGV2cyAlPiUgDQogIGZpbHRlcighc3RhdGlzdGljID09ICJQcm9wb3J0aW9uIG9mIE5ldyBWZWhpY2xlIFJlZ2lzdHJhdGlvbnMgdGhhdCBhcmUgVUxFViIpICU+JSANCiAgIyB3cml0ZV9jc3YoImRhdGEvY2xlYW5fZGF0YS90cmFuc3BvcnQvbmV3bHlfcmVnaXN0ZXJlZF92ZWhpY2xlc19hbmRfdWxldnMuY3N2IikNCiAgZ3JvdXBfYnkoeWVhciwgc3RhdGlzdGljKSAlPiUNCiAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHZhbHVlLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gJ2Ryb3BfbGFzdCcpICU+JSANCiAgc3VtbWFyaXNlKHZhbHVlID0gbGFnKHZhbHVlKS92YWx1ZSwgLmdyb3VwcyA9ICdkcm9wX2xhc3QnKSAlPiUgDQogIGRyb3BfbmEoKSAlPiUgDQogIGdncGxvdCgpICsNCiAgYWVzKHggPSB5ZWFyLCB5ID0gdmFsdWUpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkNCmBgYA0KDQoNCmBgYHtyfQ0KYmFzZV92YXIgPSAieWVhciINCmJhc2VfdmFsdWUgPSAyMDE4DQpiYXNlX21vZGlmaWVyID0gMC44DQoNCg0Kcm9hZF90cmFmZmljICU+JSANCiAgZmlsdGVyKHZlaGljbGVfdHlwZSA9PSAiQ2FycyIpICU+JSANCiAgZ3JvdXBfYnkoeWVhcikgJT4lIA0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUsIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAnZHJvcF9sYXN0JykgJT4lDQogIGdncGxvdCgpICsNCiAgYWVzKHggPSB5ZWFyLCB5ID0gdmFsdWUpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3BvaW50KGFlcyh4ID0gMjAzMCwgeSA9ICguZGF0YVtbInZhbHVlIl1dWy5kYXRhW1tiYXNlX3Zhcl1dID09IGJhc2VfdmFsdWVdKSpiYXNlX21vZGlmaWVyKSwNCiAgICAgICAgICAgICBjb2xvdXIgPSAiZGFya2dyZWVuIiwgc2hhcGUgPSAxMywgc2l6ZSA9IDUpICsNCiAgeWxpbSgwLCBOQSkNCmBgYA0KDQpgYGB7cn0NCnJvYWRfdHJhZmZpYyAlPiUgDQogIGZpbHRlciguZGF0YVtbInllYXIiXV0gPT0gMjAxOCwNCiAgICAgICAgIC5kYXRhW1sidmVoaWNsZV90eXBlIl1dID09ICJDYXJzIikgJT4lDQogIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSguZGF0YVtbInZhbHVlIl1dKSkNCmBgYA0KYGBge3J9DQpyb2FkX3RyYWZmaWNbcm9hZF90cmFmZmljW1sieWVhciJdXSA9PSAyMDE4ICYgInZlaGljbGVfdHlwZSIgPT0gIkNhcnMiLCBdWyJ2YWx1ZSJdDQpgYGANCg0KDQpgYGB7cn0NCnNhbGVzIDwtIGRhdGEuZnJhbWUoDQogIHllYXIgPSBjKDIwMDUsIDIwMDYsIDIwMDcsIDIwMDgpLA0KICBwcm9maXQgPSBjKDM0MCwgNTAwLCA2MDAsIDU1MCkNCikNCg0Kc2FsZXMgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGFlcyh4ID0geWVhciwgeSA9IHByb2ZpdCkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fcG9pbnQoYWVzKHggPSAyMDEwLCB5ID0gKC5kYXRhW1tdXVsuZGF0YVtbInllYXIiXV0gPT0gMjAwOF0qMS4xKSkpDQoNCnB1bGwoc2FsZXNbc2FsZXNbWyJ5ZWFyIl1dID09IDIwMDgsIF1bInByb2ZpdCJdKSoxLjENCmBgYA0KDQpgYGB7cn0NCg0KYGBgDQoNCg0KYGBge3J9DQpyZW1vdmUgPC0gYygieWVhciIsICJ2YWx1ZSIsICJ1bml0cyIpDQp0ZW1wIDwtIG5hbWVzKGdoZ19lbWlzc2lvbnNfY2xlYW4pDQoNCnJlbWFpbmluZ19jb2xzIDwtIHRlbXAgWyF0ZW1wICVpbiUgcmVtb3ZlXQ0KDQpnaGdfZW1pc3Npb25zX2NsZWFuICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnlfYXQocmVtYWluaW5nX2NvbHMpICU+JSANCiAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHZhbHVlLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gJ2Ryb3BfbGFzdCcpICU+JSANCiAgDQpgYGANCg0KYGBge3J9DQpzdW1tYXJpc2VkX2RhdGEgPC0gZW1pc3Npb25zX2RhdGEgJT4lIA0KICBncm91cF9hbmRfc3VtbWFyaXNlKGNjcF9tYXBwaW5nLCBwb2xsdXRhbnQpDQpgYGANCg0KYGBge3J9DQpjcmVhdGVfYmFyX3Bsb3QgPC1mdW5jdGlvbihkZiA9IHN1bW1hcmlzZWRfZGF0YSkgew0KICB4X25hbWUgPC0gbmFtZXMoZGYpWzFdDQogIA0KDQp9DQpgYGANCg0KDQoNCg0KDQpgYGB7cn0NCnRlc3RfZnVuY3Rpb24gPC0gZnVuY3Rpb24oZGYsIHZhcikgew0KICAjIGNvbnZlcnQgc25ha2VjYXNlIHZhcmlhYmxlIG5hbWUgdG8gdGl0bGUgZm9yIHVpDQogIHZhcm5hbWUgPC0gc3RyX3RvX3RpdGxlKHN0cl9yZXBsYWNlX2FsbCh2YXIsICJfIiwgIiAiKSkNCiAgDQp9DQpgYGANCg0KDQpgYGB7cn0NCg0KYGBgDQoNCg0KYGBge3J9DQpidWlsZF9zbGlkZXJfaW5wdXQgPC0gZnVuY3Rpb24oZGYsIHZhcm5hbWUpIHsNCiAgcm5nIDwtIHJhbmdlKGRmLCBuYS5ybSA9IFRSVUUpDQogIA0KICBzbGlkZXJJbnB1dCh2YXIsDQogICAgICAgICAgICAgIHBhc3RlMCh2YXJuYW1lLCAiIFJhbmdlOiIpLA0KICAgICAgICAgICAgICBtaW4gPSBybmdbMV0sDQogICAgICAgICAgICAgIG1heCA9IHJuZ1syXSwNCiAgICAgICAgICAgICAgdmFsdWUgPSBybmcsDQogICAgICAgICAgICAgIHNlcCA9ICIiLA0KICAgICAgICAgICAgICBzdGVwID0gMSwNCiAgICAgICAgICAgICAgdGlja3MgPSBGQUxTRSkNCn0NCiAgDQpgYGANCg0KYGBge3J9DQp0ZXN0X2Z1bmN0aW9uKGRmID0gZW1pc3Npb25zX2RhdGEsIHZhciA9ICJwb2xsdXRhbnQiKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCnN1YnN0cigiamV3ZWwiLCAyLCBuY2hhcigiamV3ZWwiKSkNCmBgYA0KDQoNCmBgYHtyfQ0KdGVzdCA8LSAiY2NwX21hcHBpbmdcIixcInBvbGx1dGFudCINCg0KZXZhbChwYXJzZSh0ZXh0PWdzdWIoIlxcIiwgIiIsIGRlcGFyc2UodGVzdCksIGZpeGVkPVRSVUUpKSkNCmBgYA0KYGBge3J9DQpwYXN0ZTAoYygiZmlyc3QiLCAic2Vjb25kIiksIGNvbGxhcHNlID0gIiwiKQ0KYGBgDQoNCg0KYGBge3J9DQplbWlzc2lvbnNfZGF0YSAlPiUgDQogIGdyb3VwX2J5XygiY2NwX21hcHBpbmciLCAicG9sbHV0YW50IikgJT4lIA0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUsIG5hLnJtID0gVFJVRSkpDQpgYGANCg0KDQoNCmBgYHtyfQ0KZW1pc3Npb25zX2RhdGEgJT4lIA0KICBncm91cF9ieShjY3BfbWFwcGluZywgcG9sbHV0YW50KSAlPiUgDQogIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICdkcm9wX2xhc3QnKSAlPiUgDQogIGdncGxvdCgpICsNCiAgYWVzKHggPSBuYW1lcygpWzFdLCB5ID0gdmFsdWUpICsNCiAgZ2VvbV9jb2woKQ0KYGBgDQpgYGB7cn0NCg0KYGBgDQoNCg0KYGBge3J9DQplbWlzc2lvbnNfZGF0YSA8LSByZWFkX2NzdigiZGF0YS9jbGVhbl9kYXRhL2doZ19lbWlzc2lvbnMuY3N2IikNCmBgYA0KDQpgYGB7cn0NCmVtaXNzaW9uc19kYXRhICU+JQ0KICBncm91cF9ieSh5ZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSwgbmEucm0gPSBUUlVFKSkgJT4lIA0KICBnZ3Bsb3QoKSArDQogICAgYWVzKHggPSB5ZWFyLA0KICAgICAgICB5ID0gdmFsdWUpICsNCiAgZ2VvbV9saW5lKCkgKw0KICB5bGltKDAsIE5BKQ0KYGBgDQoNCg0KT25seSBlbWlzc2lvbnMgLSA+IGVtaXNzaW9ucyB0aGF0IGFyZSBncmVhdGVyIHRoYW4gMA0KDQpgYGB7cn0NCmdoZ190cnVlX2VtaXNzaW9ucyA8LSBnaGdfZW1pc3Npb25zX2NsZWFuICU+JSANCiAgZmlsdGVyKHllYXIgPT0gbWF4KGdoZ19lbWlzc2lvbnNfY2xlYW4keWVhcikpICU+JSANCiAgZmlsdGVyKHZhbHVlID49IDApICU+JSANCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5jaGFyYWN0ZXIpLCB+c3RyX3RvX3RpdGxlKC4pKSkNCmBgYA0KDQpgYGB7cn0NCiMgbmVlZCB0byBzcGxpdCBieSBwb2xsdXRhbnQgYW5kIHllYXINCmdoZ19lbWlzc2lvbnNfY2xlYW4gJT4lIA0KICBzZWxlY3QoY2NwX21hcHBpbmcsIHNvdXJjZV9uYW1lKSAlPiUgDQogIGZpbHRlcihzdHJfZGV0ZWN0KHNvdXJjZV9uYW1lLCBwYXN0ZSgiXiIsIGNjcF9tYXBwaW5nLCBzZXAgPSAiIikpKSAlPiUgDQogIHVuaXF1ZSgpDQpgYGANCg0KYGBge3J9DQojIHZhcl9uYW1lcw0KDQoNCmBgYA0KDQpgYGB7cn0NCg0KZ2V0X2NoaWxkX2NvbHMgPC0gZnVuY3Rpb24oZGYsIGFkZGl0aW9uYWxfdmFycywgc3RhbmRhcmRfdmFycyA9IGMoInZhbHVlIiwgInVuaXRzIikpIHsNCiAgdGVtcCA8LSBuYW1lcyhkZikNCiAgcmVtb3ZlIDwtIGMoYWRkaXRpb25hbF92YXJzLCBzdGFuZGFyZF92YXJzKQ0KICANCiAgY2hpbGRfY29scyA8LSB0ZW1wIFshdGVtcCAlaW4lIHJlbW92ZV0NCn0NCg0KDQpjaGlsZF9jb2xzIDwtIGdldF9jaGlsZF9jb2xzKGdoZ193aWRlX2VtaXNzaW9ucywgYWRkaXRpb25hbF92YXJzKQ0KDQpjaGlsZF9jb2xzDQpgYGANCg0KYGBge3J9DQpjaGlsZF9jb2xzIDwtIGMoImNoaWxkX29yZGVyXzAiLCBjaGlsZF9uYW1lcykNCg0KcHJldmlvdXNfY2hpbGRyZW4gPC0gTlVMTA0KDQpoaWVyYXJjaHlfZGYgPC0gdGliYmxlKCkNCg0KZm9yIChjaGlsZCBpbiBjaGlsZF9jb2xzKSB7DQogIHByaW50KGNoaWxkKQ0KICBpbnRlcm1lZGlhdGVfdGliYmxlIDwtIGNyZWF0ZV9jaGlsZF90YWJsZShnaGdfd2lkZV9lbWlzc2lvbnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRfY2hpbGQgPSBjaGlsZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJldmlvdXNfY2hpbGRyZW4gPSBwcmV2aW91c19jaGlsZHJlbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkaXRpb25hbF92YXJzID0gYygicG9sbHV0YW50IiwgInllYXIiKSkNCiAgcHJldmlvdXNfY2hpbGRyZW4gPC0gYyhwcmV2aW91c19jaGlsZHJlbiwgY2hpbGQpDQogIGhpZXJhcmNoeV9kZiAlPiUgDQogICAgYmluZF9yb3dzKGludGVybWVkaWF0ZV90aWJibGUpDQp9DQoNCmhpZXJhcmNoeV9kZg0KYGBgDQoNCg0KDQpgYGB7cn0NCg0KYGBgDQoNCg0KDQoNCg0KYGBge3J9DQpjcmVhdGVfY2hpbGRfdGFibGUoZ2hnX3dpZGVfZW1pc3Npb25zLA0KICAgICAgICAgICAgICAgICAgIGN1cnJlbnRfY2hpbGQgPSAiY2hpbGRfb3JkZXJfMCIsDQogICAgICAgICAgICAgICAgICAgcHJldmlvdXNfY2hpbGRyZW4gPSBOVUxMLA0KICAgICAgICAgICAgICAgICAgIGFkZGl0aW9uYWxfdmFycyA9IGMoInBvbGx1dGFudCIsICJ5ZWFyIikpDQpgYGANCg0KDQpgYGB7cn0NCnByZXZpb3VzX2NoaWxkcmVuIDwtIE5VTEwNCg0KY2hpbGRyZW4gPC0gYyhwcmV2aW91c19jaGlsZHJlbiwgImNoaWxkX29yZGVyXzAiKQ0KDQpjaGlsZHJlbg0KYGBgDQoNCg0KDQpgYGB7cn0NCg0KYGBgDQpgYGB7cn0NCnJvYWRfdHJhZmZpYyA8LSByZWFkX2NzdigiZGF0YS9jbGVhbl9kYXRhL3RyYW5zcG9ydC9yb2FkX3RyYWZmaWMuY3N2IikNCmBgYA0KDQpgYGB7cn0NCnJvYWRfdHJhZmZpYyAlPiUNCiAgbXV0YXRlKHZlaGljbGVfdHlwZSA9IGlmZWxzZShzdHJfZGV0ZWN0KHZlaGljbGVfdHlwZSwgIl5BbGwgdHJhZmZpYyIpLCAiQWxsIFRyYWZmaWMiLCBzdHJfdG9fdGl0bGUodmVoaWNsZV90eXBlKSkpICU+JSANCiAgbXV0YXRlKHVuaXRzID0gIlZlaGljbGUgS2lsb21ldGVycyAoTWlsbGlvbnMpIikgJT4lIA0KICByZW5hbWUodmFsdWUgPSB2ZWhpY2xlX2tpbG9tZXRlcnNfbWlsbGlvbnMpICU+JSANCiAgd3JpdGVfY3N2KCJkYXRhL2NsZWFuX2RhdGEvdHJhbnNwb3J0L3JvYWRfdHJhZmZpYy5jc3YiKQ0KICANCmBgYA0KDQoNCmBgYHtyfQ0Kcm9hZF90cmFmZmljICU+JSANCiAgZmlsdGVyKHJvYWRfdHlwZSA9PSAiTWFqb3Igcm9hZHMgKE0gYW5kIEEpIikgJT4lDQogIGZpbHRlcighc3RyX2RldGVjdCh2ZWhpY2xlX3R5cGUsICJeQWxsIikpICU+JSANCiAgZmlsdGVyKHllYXIgPT0gMjAxOCkgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGFlcyh4ID0gLmRhdGFbWyJ2ZWhpY2xlX3R5cGUiXV0sIHkgPSB2YWx1ZSwgZmlsbCA9IC5kYXRhW1sidmVoaWNsZV90eXBlIl1dKSArDQogIGdlb21fY29sKCkgKw0KICB5bGltKDAsIE5BKQ0KYGBgDQoNCg0KYGBge3J9DQpyb2FkX3RyYWZmaWMgJT4lIA0KICBmaWx0ZXIoIXN0cl9kZXRlY3Qocm9hZF90eXBlLCAiXkFsbCIpKSAlPiUgDQogIGZpbHRlcighc3RyX2RldGVjdCh2ZWhpY2xlX3R5cGUsICJeQWxsIikpICU+JQ0KICAjIHdyaXRlX2NzdigpDQogIGdyb3VwX2J5KHllYXIpICU+JSANCiAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHZhbHVlLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gJ2Ryb3BfbGFzdCcpICU+JSANCiAgZ2dwbG90KCkgKw0KICBhZXMoeCA9IHllYXIsIHkgPSB2YWx1ZSkgKw0KICBnZW9tX2xpbmUoKQ0KYGBgDQoNCmBgYHtyfQ0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KY3JlYXRlX2NoaWxkX3RhYmxlIDwtIGZ1bmN0aW9uKGRmLCBjdXJyZW50X2NoaWxkLCBwcmV2aW91c19jaGlsZHJlbiwgYWRkaXRpb25hbF92YXJzKSB7DQogIGhpZXJhcmNoeV9kZiA8LSBnaGdfd2lkZV9lbWlzc2lvbnMgJT4lIA0KICAgIGdyb3VwX2J5XyguZG90cyA9IGMoY3VycmVudF9jaGlsZCwNCiAgICAgICAgICAgICAgICAgICAgICAgIHJldihwcmV2aW91c19jaGlsZHJlbiksDQogICAgICAgICAgICAgICAgICAgICAgICBhZGRpdGlvbmFsX3ZhcnMpKSAlPiUgDQogICAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHZhbHVlKSwgLmdyb3VwcyA9ICdkcm9wJykNCiAgDQogIGlmIChpcy5udWxsKHByZXZpb3VzX2NoaWxkcmVuKSkgew0KICAgIGhpZXJhcmNoeV9kZiAlPiUNCiAgICAgIG11dGF0ZShwYXJlbnQgPSAiIikgJT4lIA0KICAgICAgc2VsZWN0KGlkID0gY3VycmVudF9jaGlsZCwgbGFiZWwgPSBjdXJyZW50X2NoaWxkLA0KICAgICAgICAgICAgIHBhcmVudCwgYWRkaXRpb25hbF92YXJzLCB2YWx1ZSkNCiAgfSBlbHNlIHsNCiAgICBoaWVyYXJjaHlfZGYgJT4lIA0KICAgICAgdW5pdGUocHJldmlvdXNfY2hpbGRyZW4sIGNvbCA9ICJwYXJlbnQiLCBzZXAgPSAiIC0gIiwgcmVtb3ZlID0gRkFMU0UpICU+JSANCiAgICAgIHVuaXRlKGMocHJldmlvdXNfY2hpbGRyZW4sIGN1cnJlbnRfY2hpbGQpLA0KICAgICAgICAgICAgY29sID0gImlkIiwgc2VwID0gIiAtICIsIHJlbW92ZSA9IEZBTFNFKSAlPiUgDQogICAgICBzZWxlY3QoaWQsIGxhYmVsID0gY3VycmVudF9jaGlsZCwgcGFyZW50LCBhZGRpdGlvbmFsX3ZhcnMsIHZhbHVlKQ0KICB9DQp9DQpgYGANCg0KDQpgYGB7cn0NCm5hbWVzKGdoZ193aWRlX2VtaXNzaW9ucykgJWluJSAiY2hpbGRfb3JkZXJfWzAtOV0iDQogIA0KdGVtcCA8LSBuYW1lcyhnaGdfd2lkZV9lbWlzc2lvbnMpDQpyZW1vdmUgPC0gYyhhZGRpdGlvbmFsX3ZhcnMsICJ2YWx1ZSIsICJ1bml0cyIpDQoNCg0KdGVtcCBbIXRlbXAgJWluJSByZW1vdmVdDQpgYGANCg0KVE9ETzo6DQoNCmRhc2hib2FyZCAtIHJldmlldyBwYWdlDQpkYXNoYm9hcmQgLSB0cmFuc3BvcnQgZXhwbG9yZXINCg0KDQpgYGB7cn0NCmhlbHAobWFncml0dHIpDQpzYGBgDQoNCg0KYGBge3J9DQpjcmVhdGVfY2hpbGRfdGFibGUoZ2hnX3dpZGVfZW1pc3Npb25zLCBjdXJyZW50X2NoaWxkID0gImNoaWxkX29yZGVyXzAiLA0KICAgICAgICAgICAgICAgICAgIHByZXZpb3VzX2NoaWxkcmVuID0gIiIsIGFkZGl0aW9uYWxfdmFycyA9IGMoInBvbGx1dGFudCIsICJ5ZWFyIikpDQpgYGANCg0KDQpgYGB7cn0NCmNyZWF0ZV9jaGlsZF90YWJsZShnaGdfd2lkZV9lbWlzc2lvbnMsIGN1cnJlbnRfY2hpbGQgPSBjaGlsZF9vcmRlcl8wLA0KICAgICAgICAgICAgICAgICAgIHByZXZpb3VzX2NoaWxkcmVuID0gTlVMTCwgYWRkaXRpb25hbF92YXJzID0gYyhwb2xsdXRhbnQsIHllYXIpKQ0KYGBgDQoNCmBgYHtyfQ0KY3VycmVudF9jaGlsZCA8LSAiY2hpbGRfb3JkZXJfMSINCnByZXZpb3VzX2NoaWxkcmVuIDwtICJjaGlsZF9vcmRlcl8wIg0KYWRkaXRpb25hbF92YXJzIDwtIGMoInBvbGx1dGFudCIsICJ5ZWFyIikNCg0KaGllcmFyY2h5X2RmIDwtIGdoZ193aWRlX2VtaXNzaW9ucyAlPiUgDQogIGdyb3VwX2J5XyguZG90cyA9IGMoY3VycmVudF9jaGlsZCwgcmV2KHByZXZpb3VzX2NoaWxkcmVuKSwgYWRkaXRpb25hbF92YXJzKSkgJT4lIA0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpLCAuZ3JvdXBzID0gJ2Ryb3AnKQ0KDQppZiAoaXMubnVsbChwcmV2aW91c19jaGlsZHJlbikpIHsNCiAgaGllcmFyY2h5X2RmICU+JQ0KICAgIG11dGF0ZShwYXJlbnQgPSAiIikgJT4lIA0KICAgIHNlbGVjdChpZCA9IGN1cnJlbnRfY2hpbGQsIGxhYmVsID0gY3VycmVudF9jaGlsZCwgcGFyZW50LCBhZGRpdGlvbmFsX3ZhcnMsIHZhbHVlKQ0KfSBlbHNlIHsNCiAgaGllcmFyY2h5X2RmICU+JSANCiAgICB1bml0ZShwcmV2aW91c19jaGlsZHJlbiwgY29sID0gInBhcmVudCIsIHNlcCA9ICIgLSAiLCByZW1vdmUgPSBGQUxTRSkgJT4lIA0KICAgIHVuaXRlKGMocHJldmlvdXNfY2hpbGRyZW4sIGN1cnJlbnRfY2hpbGQpLCBjb2wgPSAiaWQiLCBzZXAgPSAiIC0gIiwgcmVtb3ZlID0gRkFMU0UpICU+JSANCiAgICBzZWxlY3QoaWQsIGxhYmVsID0gY3VycmVudF9jaGlsZCwgcGFyZW50LCBhZGRpdGlvbmFsX3ZhcnMsIHZhbHVlKQ0KfQ0KICANCmBgYA0KDQpgYGB7cn0NCmlmIChpcy5udWxsKHByZXZpb3VzX2NoaWxkcmVuKSkgew0KICBwcmludCgiYmVhbiIpDQp9DQpgYGANCg0KDQoNCg0KZGYgJT4lDQogIGdyb3VwX2J5KGN1cnJlbnRfY2hpbGQsIHJldihwcmV2aW91c19jaGlsZHJlbiksIGFkZGl0aW9uYWxfdmFycykgJT4lIA0KICBzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgDQogIG11dGF0ZShpZCA9IHBhc3RlKHByZXZpb3VzX2NoaWxkcmVuLCBjdXJyZW50X2NoaWxkLCBzZXAgPSAiIC0gIiksDQogICAgICAgICBwYXJlbnQgPSBwYXN0ZShwcmV2aW91c19jaGlsZHJlbiwgc2VwID0gIiAtICIpKSAlPiUgDQogIHNlbGVjdChpZCwgbGFiZWwgPSBjdXJyZW50X2NoaWxkLCBwYXJlbnQsIGFkZGl0aW9uYWxfdmFycywgdmFsdWUpDQoNCmBgYHtyfQ0KdmVjdG9yIDwtIGMoImNoaWxkXzEiLCAiY2hpbGRfMiIpDQoNCnBhc3RlKHBhc3RlKHZlY3RvciwgY29sbGFwc2UgPSAiIC0gIiksImNoaWxkXzMiLCBzZXAgPSAiIC0gIikNCmBgYA0KDQpgYGB7cn0NCnZlY3RvciA8LSBjKCkNCg0KcGFzdGUocGFzdGUodmVjdG9yLCBzZXAgPSAiIC0gIiksImNoaWxkXzMiLCBzZXAgPSAiIC0gIikNCmBgYA0KDQoNCmBgYHtyfQ0KdmVjdG9yIDwtIGMoKQ0KDQp0aWJibGUoDQogIHBhcmVudCA9IGMoImJlYW4iLCAiY3VyZCIsICJ3aGV5IiwgInNwcm91dCIsICIiKSwNCiAgcGVvcGxlID0gYygiZGF2aWQiLCAic2FzaGEiLCAiam9obiIsICJzbWl0aCIsICJkZWxpbGFoIiksDQogIHNoYXBlcyA9IGMoInRyaWFuZ2xlIiwgInJlY3RhbmdsZSIsICJzcXVhcmUiLCAiZGlhbW9uZCIsICIiKQ0KKSAlPiUgDQogIHVuaXRlKGMoMSwyLDMpLCBjb2wgPSAiaWQiLCBzZXAgPSAiIC0gIiwgcmVtb3ZlID0gRkFMU0UpDQpgYGANCg0KDQpgYGB7cn0NCnRpYmJsZSgNCiAgcGFyZW50ID0gYygiZGFkIiwgImJlYW4iLCAiIiwgImZhdmEiKSwNCiAgY2hpbGQgPSBjKCIiKQ0KKSAlPiUgDQogIHNlbGVjdChjaGlsZCkgJT4lIA0KICBwdWxsKCkNCmBgYA0KDQoNCmBgYHtyfQ0KIyBnZXQgc2VjdG9yIHRvdGFscyBmb3IgcGFyZW50IGRmICh0b3AgbGV2ZWwpDQoNCmdoZ19zZWN0b3JfdG90YWxzIDwtIGdoZ190cnVlX2VtaXNzaW9ucyAlPiUgDQogIGdyb3VwX2J5KGNjcF9tYXBwaW5nKSAlPiUgDQogIHN1bW1hcmlzZShzZWN0b3JfdG90YWwgPSBzdW0odmFsdWUpLCAuZ3JvdXBzID0gImRyb3BfbGFzdCIpDQoNCnBhcmVudF9kZiA8LSBnaGdfc2VjdG9yX3RvdGFscyAlPiUgDQogIG11dGF0ZShwYXJlbnQgPSAiIikgJT4lIA0KICBzZWxlY3QobGFiZWwgPSBjY3BfbWFwcGluZywNCiAgICAgICAgIHBhcmVudCwNCiAgICAgICAgIHZhbHVlID0gc2VjdG9yX3RvdGFsKQ0KDQojIHRoZSByZXN0IG9mIHRoZSBkYXRhDQoNCmNoaWxkcmVuX2RmIDwtIGdoZ190cnVlX2VtaXNzaW9ucyAlPiUgDQogIGZpbHRlcih5ZWFyID09IG1heChnaGdfdHJ1ZV9lbWlzc2lvbnMkeWVhcikpICU+JSANCiAgZ3JvdXBfYnkoc291cmNlX25hbWUsIGNjcF9tYXBwaW5nKSAlPiUgDQogIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSksIC5ncm91cHMgPSAiZHJvcF9sYXN0IikgJT4lIA0KICBzZWxlY3QobGFiZWwgPSBzb3VyY2VfbmFtZSwNCiAgICAgICAgIHBhcmVudCA9IGNjcF9tYXBwaW5nLA0KICAgICAgICAgdmFsdWUpDQoNCiMgY29tYmluZSBpbnRvIG9uZSBoaWVyYXJjaGljYWwgZGYsIGNyZWF0ZSBpZCBjb2x1bW4NCg0KZW1pc3Npb25zX2xvbmcgPC0gYmluZF9yb3dzKGxpc3QocGFyZW50X2RmLCBjaGlsZHJlbl9kZikpICU+JSANCiAgbXV0YXRlKGlkID0gcGFzdGUocGFyZW50LCBsYWJlbCwgc2VwID0gIiAtICIpLCAuYmVmb3JlID0gJ2xhYmVsJykgJT4lIA0KICBtdXRhdGUoaWQgPSBzdHJfcmVtb3ZlKGlkLCAiXiAtICIpKQ0KYGBgDQoNCiMgT3RoZXIgbWV0aG9kIC0gc2VwZXJhdGUgY29sdW1uDQoNCmBgYHtyfQ0KZW1pc3Npb25zX3dpZGUgPC0gZW1pc3Npb25zX2xvbmcgJT4lIA0KICBzZXBhcmF0ZShpZCwgIiAtICIsIGludG8gPSBjKCJmaXJzdCIsICJzZWNvbmQiLCAidGhpcmQiLCAiZm91cnRoIiksDQogICAgICAgICAgIHJlbW92ZSA9IEZBTFNFLCBleHRyYSA9ICJtZXJnZSIsIGZpbGwgPSAicmlnaHQiKQ0KYGBgDQoNCmBgYHtyfQ0KcGFyZW50cyA8LSBlbWlzc2lvbnNfd2lkZSAlPiUgDQogIGZpbHRlcihpcy5uYShzZWNvbmQpKSAlPiUgDQogIHNlbGVjdChpZCwgbGFiZWwsIHBhcmVudCwgdmFsdWUpDQpgYGANCg0KYGBge3J9DQpmaXJzdF9ib3JuIDwtIGVtaXNzaW9uc193aWRlICU+JSANCiAgZmlsdGVyKCFpcy5uYShzZWNvbmQpKSAlPiUgDQogIGdyb3VwX2J5KHNlY29uZCwgZmlyc3QpICU+JSANCiAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHZhbHVlKSwgLmdyb3VwcyA9ICJkcm9wX2xhc3QiKSAlPiUgDQogIG11dGF0ZShpZCA9IHBhc3RlKGZpcnN0LCBzZWNvbmQsIHNlcCA9ICIgLSAiKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBzZWxlY3QoaWQsDQogICAgICAgICBsYWJlbCA9IHNlY29uZCwNCiAgICAgICAgIHBhcmVudCA9IGZpcnN0LA0KICAgICAgICAgdmFsdWUpDQpgYGANCg0KYGBge3J9DQpzZWNvbmRfYm9ybiA8LSBlbWlzc2lvbnNfd2lkZSAlPiUgDQogIGZpbHRlcighaXMubmEodGhpcmQpKSAlPiUgDQogIGdyb3VwX2J5KHRoaXJkLCBzZWNvbmQsIGZpcnN0KSAlPiUgDQogIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSksIC5ncm91cHMgPSAiZHJvcF9sYXN0IikgJT4lIA0KICBtdXRhdGUoaWQgPSBwYXN0ZShmaXJzdCwgc2Vjb25kLCB0aGlyZCwgc2VwID0gIiAtICIpKSAlPiUgDQogIG11dGF0ZShwYXJlbnQgPSBwYXN0ZShmaXJzdCwgc2Vjb25kLCBzZXAgPSAiIC0gIikpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgc2VsZWN0KGlkLA0KICAgICAgICAgbGFiZWwgPSB0aGlyZCwNCiAgICAgICAgIHBhcmVudCwNCiAgICAgICAgIHZhbHVlKQ0KYGBgDQoNCmBgYHtyfQ0KdGhpcmRfYm9ybiA8LSBlbWlzc2lvbnNfd2lkZSAlPiUgDQogIGZpbHRlcighaXMubmEoZm91cnRoKSkgJT4lIA0KICBncm91cF9ieShmb3VydGgsIHRoaXJkLCBzZWNvbmQsIGZpcnN0KSAlPiUgDQogIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSksIC5ncm91cHMgPSAiZHJvcF9sYXN0IikgJT4lIA0KICBtdXRhdGUoaWQgPSBwYXN0ZShmaXJzdCwgc2Vjb25kLCB0aGlyZCwgZm91cnRoLCBzZXAgPSAiIC0gIikpICU+JSANCiAgbXV0YXRlKHBhcmVudCA9IHBhc3RlKGZpcnN0LCBzZWNvbmQsIHRoaXJkLCBzZXAgPSAiIC0gIikpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgc2VsZWN0KGlkLA0KICAgICAgICAgbGFiZWwgPSBmb3VydGgsDQogICAgICAgICBwYXJlbnQsDQogICAgICAgICB2YWx1ZSkNCmBgYA0KDQpgYGB7cn0NCiMgdGhlIG51bWJlciBvZiBwb3RlbnRpYWwgY2hpbGQgbGF5ZXJzIGlzIHRoZSBtYXhpbXVtIGluY2x1ZGVkIGluIHRoZSBkYXRhc2V0DQpuX3BvdGVudGlhbF9jaGlsZF9sYXllcnMgPC0gZW1pc3Npb25zX2xvbmcgJT4lIA0KICBzZWxlY3QoaWQpICU+JSANCiAgcHVsbCgpICU+JSANCiAgc3RyX2NvdW50KCIgLSAiKSAlPiUgDQogIG1heCgpDQpgYGANCg0KDQoNCmBgYHtyfQ0KY3JlYXRlX2hpZXJhcmNoeV9kZiA8LSBmdW5jdGlvbihkZiwgaWRfY29sID0gImlkIiwgaWRfc2VwID0gIiAtICIpIHsNCiAgbl9wb3RlbnRpYWxfY2hpbGRfbGF5ZXJzIDwtIGRmICU+JSANCiAgICBzZWxlY3QoY29sKSAlPiUgDQogICAgcHVsbCgpICU+JSANCiAgICBzdHJfY291bnQoc2VwKSAlPiUgDQogICAgbWF4KCkNCiAgDQogIA0KfQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmBgYA0KDQoNCmBgYHtyfQ0KZW1pc3Npb25zX2xvbmcgPC0gYmluZF9yb3dzKGxpc3QocGFyZW50cywgZmlyc3RfYm9ybiwgc2Vjb25kX2Jvcm4sIHRoaXJkX2Jvcm4pKSAlPiUgDQogIG11dGF0ZSh1bml0cyA9IGdoZ19lbWlzc2lvbnNfY2xlYW4kdW5pdHNbMV0pICU+JSANCiAgd3JpdGVfY3N2KCJkYXRhL2NsZWFuX2RhdGEvaGllcmFyY2hpY2FsX2RhdGEuY3N2IikNCmBgYA0KDQoNCg0KYGBge3J9DQplbWlzc2lvbnNfbG9uZyAlPiUNCiAgZGF0YS5mcmFtZShzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpICU+JSANCiAgcGxvdF9seSgNCiAgICBpZHMgPSB+aWQsDQogICAgbGFiZWxzID0gfmxhYmVsLA0KICAgIHBhcmVudHMgPSB+cGFyZW50LA0KICAgIHZhbHVlcyA9IH52YWx1ZSwNCiAgICB0eXBlID0gInRyZWVtYXAiLA0KICAgIGJyYW5jaHZhbHVlcyA9ICJ0b3RhbCIsDQogICAgbWF4ZGVwdGggPSAyLA0KICAgIHRleHRpbmZvPSdsYWJlbCtwZXJjZW50IHJvb3QrZW50cnknDQogICkNCmBgYA0KDQoNCmBgYHtyfQ0KZmlsdGVyZWRfZ2hnX2hpZXJjaGFyeSA8LSBnaGdfaGllcmNoYXJ5ICU+JSANCiAgZmlsdGVyKHllYXIgPT0gMTk5MCkgJT4lDQogIGZpbHRlcihwb2xsdXRhbnQgJWluJSBjKCJDTzIiLCAiTjJPIikpDQoNCmVtaXNzaW9ucyA8LSBmaWx0ZXJlZF9naGdfaGllcmNoYXJ5ICU+JSANCiAgZmlsdGVyKCF2YWx1ZSA8IDApICU+JSANCiAgZ3JvdXBfYnkoaWQsIGxhYmVsLCBwYXJlbnQpICU+JSANCiAgc3VtbWFyaXNlKHZhbHVlID0gc3VtKHZhbHVlLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gJ2Ryb3BfbGFzdCcpICU+JSANCiAgbXV0YXRlKHVuaXRzID0gIm1lZ2F0b25uZXMgb2YgQ08yIGVxdWl2ZWxhbnQiKQ0KDQpzaW5rcyA8LSBmaWx0ZXJlZF9naGdfaGllcmNoYXJ5ICU+JSANCiAgZmlsdGVyKHZhbHVlIDwgMCkgJT4lIA0KICBtdXRhdGUodmFsdWUgPSB2YWx1ZSAqIC0xKSAlPiUgDQogIGdyb3VwX2J5KGlkLCBsYWJlbCwgcGFyZW50KSAlPiUgDQogIHN1bW1hcmlzZSh2YWx1ZSA9IHN1bSh2YWx1ZSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICdkcm9wX2xhc3QnKSAlPiUgDQogIG11dGF0ZSh1bml0cyA9ICJtZWdhdG9ubmVzIG9mIENPMiBlcXVpdmVsYW50IikNCg0KZW1pc3Npb25zICU+JSANCiAgZGF0YS5mcmFtZShzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpICU+JSANCiAgcGxvdF9seSgNCiAgICBpZHMgPSB+aWQsDQogICAgbGFiZWxzID0gfmxhYmVsLA0KICAgIHBhcmVudHMgPSB+cGFyZW50LA0KICAgIHZhbHVlcyA9IH52YWx1ZSwNCiAgICB0eXBlID0gInN1bmJ1cnN0IiwNCiAgICBtYXhkZXB0aCA9IDIsDQogICAgaW5zaWRldGV4dG9yaWVudGF0aW9uID0gJ3JhZGlhbCcsDQogICAgbWFya2VyPWxpc3QoY29sb3JzY2FsZT0nVmlyaWRpcycpLA0KICAgIHRleHQgPSB+dW5pdHMsDQogICAgdGV4dGluZm89J2xhYmVsK3BlcmNlbnQgcm9vdCt2YWx1ZScsDQogICAgaG92ZXJpbmZvID0gcGFzdGUoIiV7bGFiZWx9OiA8YnI+JXt2YWx1ZX0iLCd0ZXh0JykNCiAgKQ0KYGBgDQoNCg0KYGBge3J9DQoNCmBgYA0KDQoNCg0KYGBge3J9DQpwbG90X2x5KA0KICBsYWJlbHMgPSBjKCJFdmUiLCAiU2V0aCIsICJFbm9zIiwgIk5vYW0iLCAiQXdhbiIsICJFbm9jaCIpLA0KICBwYXJlbnRzID0gYygiIiwgIkV2ZSIsICJTZXRoIiwgIlNldGgiLCAiRXZlIiwgIkF3YW4iKSwNCiAgdmFsdWVzID0gYygxNiwgMTIsIDEwLCAyLCA0LCA0KSwNCiAgdHlwZSA9ICJzdW5idXJzdCIsDQogIGJyYW5jaHZhbHVlcyA9ICJ0b3RhbCINCikNCmBgYA0KDQpgYGB7cn0NCnRpYmJsZSgNCiAgbGFiZWxzID0gYygiRXZlIiwgIlNldGgiLCAiRW5vcyIsICJOb2FtIiwgIkF3YW4iLCAiRW5vY2giKSwNCiAgcGFyZW50cyA9IGMoIiIsICJFdmUiLCAiU2V0aCIsICJTZXRoIiwgIkV2ZSIsICJBd2FuIiksDQogIHZhbHVlcyA9IGMoMTYsIDEyLCAxMCwgMiwgNCwgNCkNCikNCmBgYA0KDQpgYGB7cn0NCmVtaXNzaW9uc19sb25nDQpgYGANCg0KDQpgYGB7cn0NCmZpZyA8LSBwbG90X2x5KA0KICBsYWJlbHMgPSBjYWluX2JsZSRsYWJlbHMsDQogIHBhcmVudHMgPSBjYWluX2JsZSRwYXJlbnRzLA0KICB2YWx1ZXMgPSBjYWluX2JsZSR2YWx1ZXMsDQogIHR5cGUgPSAnc3VuYnVyc3QnDQopDQoNCmZpZw0KYGBgDQoNCg0KYGBge3J9DQplbWlzc2lvbnNfbG9uZyRsYWJlbFsxOjEwXQ0KYGBgDQoNCg0KYGBge3J9DQpkIDwtIGRhdGEuZnJhbWUoDQogICAgaWRzID0gYygNCiAgICAiTm9ydGggQW1lcmljYSIsICJFdXJvcGUiLCAiQXVzdHJhbGlhIiwgIk5vcnRoIEFtZXJpY2EgLSBGb290YmFsbCIsICJTb2NjZXIiLA0KICAgICJOb3J0aCBBbWVyaWNhIC0gUnVnYnkiLCAiRXVyb3BlIC0gRm9vdGJhbGwiLCAiUnVnYnkiLA0KICAgICJFdXJvcGUgLSBBbWVyaWNhbiBGb290YmFsbCIsIkF1c3RyYWxpYSAtIEZvb3RiYWxsIiwgIkFzc29jaWF0aW9uIiwNCiAgICAiQXVzdHJhbGlhbiBSdWxlcyIsICJBdXRzdHJhbGlhIC0gQW1lcmljYW4gRm9vdGJhbGwiLCAiQXVzdHJhbGlhIC0gUnVnYnkiLA0KICAgICJSdWdieSBMZWFndWUiLCAiUnVnYnkgVW5pb24iDQogICksDQogIGxhYmVscyA9IGMoDQogICAgIk5vcnRoPGJyPkFtZXJpY2EiLCAiRXVyb3BlIiwgIkF1c3RyYWxpYSIsICJGb290YmFsbCIsICJTb2NjZXIiLCAiUnVnYnkiLA0KICAgICJGb290YmFsbCIsICJSdWdieSIsICJBbWVyaWNhbjxicj5Gb290YmFsbCIsICJGb290YmFsbCIsICJBc3NvY2lhdGlvbiIsDQogICAgIkF1c3RyYWxpYW48YnI+UnVsZXMiLCAiQW1lcmljYW48YnI+Rm9vdGJhbGwiLCAiUnVnYnkiLCAiUnVnYnk8YnI+TGVhZ3VlIiwNCiAgICAiUnVnYnk8YnI+VW5pb24iDQogICksDQogIHBhcmVudHMgPSBjKA0KICAgICIiLCAiIiwgIiIsICJOb3J0aCBBbWVyaWNhIiwgIk5vcnRoIEFtZXJpY2EiLCAiTm9ydGggQW1lcmljYSIsICJFdXJvcGUiLA0KICAgICJFdXJvcGUiLCAiRXVyb3BlIiwiQXVzdHJhbGlhIiwgIkF1c3RyYWxpYSAtIEZvb3RiYWxsIiwgIkF1c3RyYWxpYSAtIEZvb3RiYWxsIiwNCiAgICAiQXVzdHJhbGlhIC0gRm9vdGJhbGwiLCAiQXVzdHJhbGlhIC0gRm9vdGJhbGwiLCAiQXVzdHJhbGlhIC0gUnVnYnkiLA0KICAgICJBdXN0cmFsaWEgLSBSdWdieSINCiAgKSwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCmZpZyA8LSBwbG90X2x5KGQsIGlkcyA9IH5pZHMsIGxhYmVscyA9IH5sYWJlbHMsIHBhcmVudHMgPSB+cGFyZW50cywgdHlwZSA9ICdzdW5idXJzdCcpDQoNCmQNCmBgYA0KDQpgYGB7cn0NCmNsYXNzKGVtaXNzaW9uc19sb25nKQ0KYGBgDQpgYGB7cn0NCmNsYXNzKGNhaW5fYmxlKQ0KYGBgDQoNCg0KYGBge3J9DQpkaWZmX29yZGVyIDwtIGdoZ19lbWlzc2lvbnNfY2xlYW4gJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY2NwX21hcHBpbmcsIHllYXIsIHBvbGx1dGFudCkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKHZhbHVlID0gc3VtKHZhbHVlKSwgdW5pdHMgPSB1bml0c1sxXSwgLmdyb3VwcyA9ICJrZWVwIikgJT4lDQogIGZpbHRlcihwb2xsdXRhbnQgPT0gIkNPMiIpICU+JSANCiAgZmlsdGVyKHllYXIgPT0gbWluKGdoZ19lbWlzc2lvbnNfY2xlYW4keWVhcikgfA0KICAgICAgICAgICB5ZWFyID09IG1heChnaGdfZW1pc3Npb25zX2NsZWFuJHllYXIpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIGdyb3VwX2J5KGNjcF9tYXBwaW5nKSAlPiUgDQogIG11dGF0ZShkaWZmID0gbGFnKHZhbHVlKSAtIHZhbHVlKSAlPiUgDQogIGFycmFuZ2UoZGlmZikgJT4lDQogIGRyb3BfbmEoKSAlPiUgDQogIHNlbGVjdChjY3BfbWFwcGluZykgJT4lIA0KICBwdWxsKCkNCmBgYA0KDQoNCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19jbGVhbiAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjY3BfbWFwcGluZywgeWVhciwgcG9sbHV0YW50KSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UodmFsdWUgPSBzdW0odmFsdWUpLCB1bml0cyA9IHVuaXRzWzFdLCAuZ3JvdXBzID0gImtlZXAiKSAlPiUNCiAgZmlsdGVyKHBvbGx1dGFudCA9PSAiQ08yIikgJT4lDQogIG11dGF0ZShjY3BfbWFwcGluZyA9IGZhY3RvcihjY3BfbWFwcGluZywgbGV2ZWxzID0gcmV2KGRpZmZfb3JkZXIpKSkgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGFlcyh4ID0geWVhciwgeSA9IHZhbHVlLCBmaWxsID0gY2NwX21hcHBpbmcpICsNCiAgZ2VvbV9hcmVhKCkgKw0KICBmYWNldF93cmFwKH5wb2xsdXRhbnQpICsNCiAgdGhlbWVfYncoKQ0KYGBgDQpgYGB7cn0NCmdoZ19lbWlzc2lvbnNfY2xlYW4gJT4lIA0KICBncm91cF9ieShwb2xsdXRhbnQpICU+JSANCiAgc3VtbWFyaXNlKGVtaXNzaW9ucyA9IHN1bSh2YWx1ZSkpDQpgYGANCg0KDQpgYGB7cn0NCnBsb3RseTo6Z2dwbG90bHkoDQogIGdoZ19lbWlzc2lvbnNfY2xlYW4gJT4lIA0KICAgIGZpbHRlcih5ZWFyID09IDIwMTgpICU+JQ0KICAgIGZpbHRlcihwb2xsdXRhbnQgJWluJSBjKCJDTzIiLCAiQ0g0IikpICU+JQ0KICAgIGdncGxvdCgpICsNCiAgICBhZXMoeCA9IGZhY3RvcihjY3BfbWFwcGluZywgbGV2ZWxzID0gcmV2KGxldmVscyhmYWN0b3IoY2NwX21hcHBpbmcpKSkpLA0KICAgICAgICB5ID0gdmFsdWUsIGZpbGwgPSBzb3VyY2VfbmFtZSwNCiAgICAgICAgdGV4dCA9IHBhc3RlMCgnPC9icj4gU2VjdG9yOiAnLCBjY3BfbWFwcGluZywNCiAgICAgICAgICAgICAgICAgICAgICAnPC9icj4gRW1pc3Npb25zOiAnLCB2YWx1ZSwNCiAgICAgICAgICAgICAgICAgICAgICAnPC9icj4gU291cmNlIE5hbWU6ICcsIHNvdXJjZV9uYW1lKSkgKw0KICAgIGdlb21fY29sKHBvc2l0aW9uID0gInN0YWNrIikgKw0KICAgIHRoZW1lX2J3KCkgKw0KICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICAgIGxhYnMoeCA9ICJTZWN0b3IiLA0KICAgICAgICAgeSA9IHBhc3RlMCgiRW1pc3Npb25zICgiLCBnaGdfZW1pc3Npb25zX2NsZWFuJHVuaXRzWzFdLCAiKSIpKSArDQogICAgY29vcmRfZmxpcCgpLA0KICAgIHRvb2x0aXAgPSAndGV4dCcNCiAgKQ0KDQpgYGANCg0KDQpgYGB7cn0NCmdoZ19lbWlzc2lvbnNfZGF0YSAlPiUgDQogIG5hbWVzKCkNCmBgYA0KDQpgYGB7cn0NCmdoZ19lbWlzc2lvbnNfZGF0YSAlPiUgDQogIHNlbGVjdCgpDQpgYGANCg0KDQoNCmBgYHtyfQ0KaW5wdXQgPC0gbGlzdCgpDQoNCmlucHV0JGNvbF9jaG9pY2UgPSAibmF0aW9uYWxfY29tbXVuaWNhdGlvbl9jYXRlZ29yaWVzIg0KYGBgDQoNCg0KDQpgYGB7cn0NCmdoZ19lbWlzc2lvbnNfY2xlYW4gJT4lDQogIGdyb3VwX2J5XyhpbnB1dCRjb2xfY2hvaWNlLCAiZW1pc3Npb25feWVhciIpICU+JSANCiAgc3VtbWFyaXNlKHRvdGFsX2doZ19lbWlzc2lvbnMgPSBzdW0oZW1pc3Npb25zKSkgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGFlcyh4ID0gRW1pc3Npb25ZZWFyLCB5ID0gdG90YWxfZ2hnX2VtaXNzaW9ucywgZ3JvdXAgPSBgTmF0aW9uYWwgQ29tbXVuaWNhdGlvbiBDYXRlZ29yaWVzYCwgY29sb3VyID0gYE5hdGlvbmFsIENvbW11bmljYXRpb24gQ2F0ZWdvcmllc2ApICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDE5OTAsMjAyMCw1KSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAwKQ0KYGBgDQoNCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19kYXRhICU+JSANCiAgZGlzdGluY3QoYE5hdGlvbmFsIENvbW11bmljYXRpb24gQ2F0ZWdvcmllc2ApDQpgYGANCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19kYXRhICU+JSANCiAgZmlsdGVyKEVtaXNzaW9uWWVhciAhPSAiQmFzZVllYXIiKSAlPiUgDQogIG11dGF0ZShFbWlzc2lvblllYXIgPSBhcy5udW1lcmljKEVtaXNzaW9uWWVhcikpICU+JSANCiAgZ3JvdXBfYnkoRW1pc3Npb25ZZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh0b3RhbF9naGdfZW1pc3Npb25zID0gc3VtKGBFbWlzc2lvbnMgKE10Q08yZSlgKSkgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGFlcyh4ID0gRW1pc3Npb25ZZWFyLCB5ID0gdG90YWxfZ2hnX2VtaXNzaW9ucykgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTk5MCwyMDIwLDUpKSArDQogIHlsaW0oMCwgODApICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gMCkgKw0KICB0aGVtZV9idygpDQpgYGANCg0KDQpgYGB7cn0NCmdoZ19lbWlzc2lvbnNfZGF0YSAlPiUgDQogIGRpc3RpbmN0KGBDQ1AgbWFwcGluZ2ApDQpgYGANCg0KYGBge3J9DQoNCmBgYA0KDQoNCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19kYXRhICU+JSANCiAgZGlzdGluY3QoYE5hdGlvbmFsIENvbW11bmljYXRpb24gQ2F0ZWdvcmllc2ApDQpgYGANCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19kYXRhDQpgYGANCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19kYXRhICU+JSANCiAgZmlsdGVyKEVtaXNzaW9uWWVhciAhPSAiQmFzZVllYXIiKSAlPiUgDQogIG11dGF0ZShFbWlzc2lvblllYXIgPSBhcy5udW1lcmljKEVtaXNzaW9uWWVhcikpICU+JSANCiAgZ3JvdXBfYnkoYENDUCBtYXBwaW5nYCwgRW1pc3Npb25ZZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh0b3RhbF9naGdfZW1pc3Npb25zID0gc3VtKGBFbWlzc2lvbnMgKE10Q08yZSlgKSkgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGFlcyh4ID0gRW1pc3Npb25ZZWFyLCB5ID0gdG90YWxfZ2hnX2VtaXNzaW9ucywgZ3JvdXAgPSBgQ0NQIG1hcHBpbmdgLCBjb2xvdXIgPSBgQ0NQIG1hcHBpbmdgKSArDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxOTkwLDIwMjAsNSkpDQpgYGANCg0KYGBge3J9DQpnaGdfZW1pc3Npb25zX2RhdGEgJT4lIA0KICBmaWx0ZXIoRW1pc3Npb25ZZWFyICE9ICJCYXNlWWVhciIpICU+JSANCiAgbXV0YXRlKEVtaXNzaW9uWWVhciA9IGFzLm51bWVyaWMoRW1pc3Npb25ZZWFyKSkgJT4lIA0KICBmaWx0ZXIoYE5hdGlvbmFsIENvbW11bmljYXRpb24gQ2F0ZWdvcmllc2AgIT0gYENDUCBtYXBwaW5nYCkgJT4lIA0KICBzZWxlY3QoYE5hdGlvbmFsIENvbW11bmljYXRpb24gQ2F0ZWdvcmllc2AsIGBDQ1AgbWFwcGluZ2ApICU+JSANCiAgdW5pcXVlKCkNCmBgYA0KY2F0ZWdvcnlfaWQsY2F0ZWdvcnlfbmFtZSxzdWJjYXRlZ29yeV9pZCxzdWJjYXRlZ29yeV9uYW1lLHllYXIsZW1pc3Npb25zLGVtaXNzaW9uDQoNCmBgYHtyfQ0KZW1pc3Npb25zX3NhbmtleSA8LSBlbWlzc2lvbnNfZGF0YSAlPiUgDQogIHNlbGVjdChjY3BfbWFwcGluZywgc291cmNlX25hbWUsIHBvbGx1dGFudCwgZW1pc3Npb25feWVhciwgZW1pc3Npb25zLCB1bml0cykNCmBgYA0KDQoNCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19jbGVhbg0KYGBgDQoNCg0KYGBge3J9DQpmaWx0ZXJlZF9kZiA8LSBnaGdfZW1pc3Npb25zX2NsZWFuICU+JSANCiAgc2VsZWN0KGNjcF9tYXBwaW5nLCBzb3VyY2VfbmFtZSwgcG9sbHV0YW50LCBlbWlzc2lvbl95ZWFyLCBlbWlzc2lvbnMsIHVuaXRzKSAlPiUgDQogIGZpbHRlcihwb2xsdXRhbnQgPT0gIkNPMiIpICU+JSANCiAgZmlsdGVyKGVtaXNzaW9uX3llYXIgPT0gIjIwMDUiKQ0KYGBgDQoNCmBgYHtyfQ0KdG90YWxfZW1pc3Npb25zX2Zvcl9nYXMgPC0gZmlsdGVyZWRfZGYgJT4lIA0KICBzdW1tYXJpc2Uoc3VtKGVtaXNzaW9ucykpICU+JSANCiAgcHVsbCgpDQoNCnRvdGFsX2VtaXNzaW9uc19ieV9jYXRlZ29yeSA8LSBmaWx0ZXJlZF9kZiAlPiUgDQogIHNlbGVjdCgtcG9sbHV0YW50KSAlPiUgDQogIGdyb3VwX2J5KGNjcF9tYXBwaW5nKSAlPiUgDQogIHN1bW1hcmlzZShjYXRfc3VtID0gc3VtKGVtaXNzaW9ucyksIC5ncm91cHMgPSAnZHJvcF9sYXN0JykNCmBgYA0KDQpgYGB7cn0NCmNhdGVnb3JpZXMgPC0gZmlsdGVyZWRfZGYgJT4lIA0KICBkaXN0aW5jdChjY3BfbWFwcGluZykgJT4lIA0KICBwdWxsKCkNCg0Kbl9jYXRlZ29yaWVzIDwtIGxlbmd0aChjYXRlZ29yaWVzKQ0KDQpzb3VyY2VzIDwtIGZpbHRlcmVkX2RmICU+JSANCiAgZGlzdGluY3Qoc291cmNlX25hbWUpICU+JSANCiAgcHVsbCgpDQoNCm5fc291cmNlcyA8LSBsZW5ndGgoc291cmNlcykNCmBgYA0KDQpgYGB7cn0NCm5fc291cmNlcw0KYGBgDQoNCg0KYGBge3J9DQpub2RlX25hbWVzIDwtIGMoIlRvdGFsIiwgY2F0ZWdvcmllcywgc291cmNlcywgIk90aGVyIikNCg0Kbm9kZV9uYW1lc19kZiA8LSBkYXRhLmZyYW1lKCJuYW1lIiA9IG5vZGVfbmFtZXMpDQoNCnRvdGFsX3NhbmtleV90aWJibGUgPC0gdG90YWxfZW1pc3Npb25zX2J5X2NhdGVnb3J5ICU+JQ0KICBtdXRhdGUodG90YWwgPSAiVG90YWwiKSAlPiUgDQogIG11dGF0ZSh0b3RhbCA9IG1hdGNoKHRvdGFsLCBub2RlX25hbWVzKSAtMSkgJT4lIA0KICBtdXRhdGUoY2NwX21hcHBpbmcgPSBtYXRjaChjY3BfbWFwcGluZywgbm9kZV9uYW1lcykgLTEpICU+JSANCiAgc2VsZWN0KHNvdXJjZSA9IHRvdGFsLA0KICAgICAgICAgdGFyZ2V0ID0gY2NwX21hcHBpbmcsDQogICAgICAgICB2YWx1ZSA9IGNhdF9zdW0pDQoNCnRvdGFsX2ZpbHRlcmVkX2VtaXNzaW9ucyA8LSB0b3RhbF9zYW5rZXlfdGliYmxlICU+JSANCiAgc3VtbWFyaXNlKHN1bSh2YWx1ZSkpICU+JSANCiAgcHVsbCgpDQoNCm90aGVyX2VtaXNzaW9ucyA8LSB0b3RhbF9lbWlzc2lvbnNfZm9yX2dhcyAtIHRvdGFsX2ZpbHRlcmVkX2VtaXNzaW9ucw0KDQp0b3RhbF9vdGhlcl9zYW5rZXlfdGliYmxlIDwtIHRpYmJsZSgNCiAgInNvdXJjZSIgPSBjKDApLA0KICAidGFyZ2V0IiA9IChtYXRjaCgiT3RoZXIiLCBub2RlX25hbWVzKSAtMSksDQogICJ2YWx1ZSIgPSBjKG90aGVyX2VtaXNzaW9ucykNCikNCg0KDQpzdWJfc2Fua2V5X3RpYmJsZSA8LSBmaWx0ZXJlZF9kZiAlPiUgDQogIHNlbGVjdCgtIGModW5pdHMsIHBvbGx1dGFudCwgZW1pc3Npb25feWVhcikpICU+JSANCiAgbXV0YXRlKGNjcF9tYXBwaW5nID0gbWF0Y2goY2NwX21hcHBpbmcsIG5vZGVfbmFtZXMpIC0xLA0KICAgICAgICAgc291cmNlX25hbWUgPSBtYXRjaChzb3VyY2VfbmFtZSwgbm9kZV9uYW1lcykgLTEpDQoNCm5hbWVzKHN1Yl9zYW5rZXlfdGliYmxlKSA9IGMoInNvdXJjZSIsICJ0YXJnZXQiLCAidmFsdWUiKQ0KDQpzYW5rZXlfdGliYmxlIDwtIHRvdGFsX3NhbmtleV90aWJibGUgJT4lIA0KICBiaW5kX3Jvd3Moc3ViX3NhbmtleV90aWJibGUpICU+JSANCiAgYmluZF9yb3dzKHRvdGFsX290aGVyX3NhbmtleV90aWJibGUpDQoNCmxpbmtzX21hdHJpeCA8LSBkYXRhLmZyYW1lKGFzLm1hdHJpeChzYW5rZXlfdGliYmxlLCBieXJvdyA9IFRSVUUsIG5jb2xzID0gMykpDQoNCiMgQWRkIGEgJ2dyb3VwJyBjb2x1bW4gdG8gZWFjaCBjb25uZWN0aW9uOg0KbGlua3MgPC0gbGlua3NfbWF0cml4ICU+JSANCiAgbXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKA0KICAgIHNvdXJjZSA9PSAwIH4gcGFzdGUoInR5cGVfIiwgdGFyZ2V0LCBzZXAgPSAiIiksDQogICAgc291cmNlIT0wIH4gcGFzdGUoInR5cGVfIiwgc291cmNlLCBzZXAgPSAiIikNCiAgKSkNCg0Kbm9kZXMgPC0gbm9kZV9uYW1lc19kZg0KIyBBZGQgYSAnZ3JvdXAnIGNvbHVtbiB0byBlYWNoIG5vZGUuDQojIEFsbCBvZiB0aGVtIGluIHRoZSBzYW1lIGdyb3VwIHRvIG1ha2UgdGhlbSB0aGUgc2FtZSBjb2xvdXINCm5vZGVzJGdyb3VwIDwtIGFzLmZhY3RvcihjKCJteV91bmlxdWVfZ3JvdXAiKSkNCg0KZW1pc3Npb25zIDwtIGxpc3QoKQ0KDQplbWlzc2lvbnMkbm9kZXMgPC0gbm9kZXMNCmVtaXNzaW9ucyRsaW5rcyA8LSBsaW5rcw0KDQoNCmBgYA0KDQoNCg0KDQoNCg0KYGBge3J9DQp0b3RhbF9maWx0ZXJlZF9lbWlzc2lvbnMgPC0gdG90YWxfc2Fua2V5X3RpYmJsZSAlPiUgDQogIHN1bW1hcmlzZShzdW0odmFsdWUpKSAlPiUgDQogIHB1bGwoKQ0KDQpvdGhlcl9lbWlzc2lvbnMgPC0gdG90YWxfZW1pc3Npb25zX2Zvcl9nYXMgLSB0b3RhbF9maWx0ZXJlZF9lbWlzc2lvbnMNCg0KdG90YWxfb3RoZXJfc2Fua2V5X3RpYmJsZSA8LSB0aWJibGUoDQogICJzb3VyY2UiID0gYygwKSwNCiAgInRhcmdldCIgPSAobWF0Y2goIk90aGVyIiwgbm9kZV9uYW1lcykgLTEpLA0KICAidmFsdWUiID0gYyhvdGhlcl9lbWlzc2lvbnMpDQopDQoNCnN1Yl9zYW5rZXlfdGliYmxlIDwtIGZpbHRlcmVkX3RpYmJsZSAlPiUgDQogIHNlbGVjdCgtY2F0ZWdvcnlfaWQsIC1zdWJjYXRlZ29yeV9pZCwgLXllYXIpICU+JSANCiAgbXV0YXRlKGNhdGVnb3J5X25hbWUgPSBtYXRjaChjYXRlZ29yeV9uYW1lLCBub2RlX25hbWVzKSAtMSwNCiAgICAgICAgIHN1YmNhdGVnb3J5X25hbWUgPSBtYXRjaChzdWJjYXRlZ29yeV9uYW1lLCBub2RlX25hbWVzKSAtMSkNCg0KbmFtZXMoc3ViX3NhbmtleV90aWJibGUpID0gYygic291cmNlIiwgInRhcmdldCIsICJ2YWx1ZSIpDQoNCnNhbmtleV90aWJibGUgPC0gdG90YWxfc2Fua2V5X3RpYmJsZSAlPiUgDQogIGJpbmRfcm93cyhzdWJfc2Fua2V5X3RpYmJsZSkgJT4lIA0KICBiaW5kX3Jvd3ModG90YWxfb3RoZXJfc2Fua2V5X3RpYmJsZSkNCg0KbGlua3NfbWF0cml4IDwtIGRhdGEuZnJhbWUoYXMubWF0cml4KHNhbmtleV90aWJibGUsIGJ5cm93ID0gVFJVRSwgbmNvbHMgPSAzKSkNCg0KIyBBZGQgYSAnZ3JvdXAnIGNvbHVtbiB0byBlYWNoIGNvbm5lY3Rpb246DQpsaW5rcyA8LSBsaW5rc19tYXRyaXggJT4lIA0KICBtdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oDQogICAgc291cmNlID09IDAgfiBwYXN0ZSgidHlwZV8iLCB0YXJnZXQsIHNlcCA9ICIiKSwNCiAgICBzb3VyY2UhPTAgfiBwYXN0ZSgidHlwZV8iLCBzb3VyY2UsIHNlcCA9ICIiKQ0KICApKQ0KDQpub2RlcyA8LSBub2RlX25hbWVzX2RmDQojIEFkZCBhICdncm91cCcgY29sdW1uIHRvIGVhY2ggbm9kZS4NCiMgQWxsIG9mIHRoZW0gaW4gdGhlIHNhbWUgZ3JvdXAgdG8gbWFrZSB0aGVtIHRoZSBzYW1lIGNvbG91cg0Kbm9kZXMkZ3JvdXAgPC0gYXMuZmFjdG9yKGMoIm15X3VuaXF1ZV9ncm91cCIpKQ0KDQplbWlzc2lvbnMgPC0gbGlzdCgpDQoNCmVtaXNzaW9ucyRub2RlcyA8LSBub2Rlcw0KZW1pc3Npb25zJGxpbmtzIDwtIGxpbmtzDQpgYGANCg0KDQoNCg0KDQoNCg0KDQpgYGB7cn0NCm1ha2Vfc2Fua2V5X2RmcyA8LSBmdW5jdGlvbihkYXRhLCB1c2VyWWVhciwgdXNlckdhcykgew0KICBuX2NhdGVnb3JpZXMgPC0gZGF0YSAlPiUgDQogICAgZGlzdGluY3QoY2F0ZWdvcnlfbmFtZSkgJT4lIA0KICAgIG5yb3coKQ0KICANCiAgdG90YWxfZW1pc3Npb25zX2Zvcl9nYXMgPC0gZGF0YSAlPiUgDQogICAgZmlsdGVyKGVtaXNzaW9uID09IHVzZXJHYXMoKSkgJT4lIA0KICAgIGZpbHRlcih5ZWFyID09IHVzZXJZZWFyKCkpICU+JQ0KICAgIHN1bW1hcmlzZShzdW0oZW1pc3Npb25zKSkgJT4lIA0KICAgIHB1bGwoKQ0KICANCiAgZmlsdGVyZWRfdGliYmxlIDwtIGRhdGEgJT4lDQogICAgZmlsdGVyKGVtaXNzaW9uID09IHVzZXJHYXMoKSkgJT4lIA0KICAgIHNlbGVjdCgtZW1pc3Npb24pICU+JSANCiAgICBmaWx0ZXIoeWVhciA9PSB1c2VyWWVhcigpKSAlPiUgDQogICAgZmlsdGVyKGVtaXNzaW9ucyA+IHVzZXJSZXNvbHV0aW9uKCkpDQogIA0KICB0b3RhbF9lbWlzc2lvbnNfYnlfY2F0IDwtIGZpbHRlcmVkX3RpYmJsZSAlPiUNCiAgICBncm91cF9ieShjYXRlZ29yeV9uYW1lKSAlPiUgDQogICAgc3VtbWFyaXNlKGNhdF9zdW0gPSBzdW0oZW1pc3Npb25zKSwgLmdyb3VwcyA9ICdkcm9wX2xhc3QnKQ0KICANCiAgY2F0ZWdvcmllcyA8LSBmaWx0ZXJlZF90aWJibGUgJT4lDQogICAgZGlzdGluY3QoY2F0ZWdvcnlfbmFtZSkgJT4lIA0KICAgIHB1bGwoKQ0KICANCiAgc3ViY2F0ZWdvcmllcyA8LSBmaWx0ZXJlZF90aWJibGUgJT4lDQogICAgZGlzdGluY3Qoc3ViY2F0ZWdvcnlfbmFtZSkgJT4lIA0KICAgIHB1bGwoKQ0KICANCiAgbm9kZV9uYW1lcyA8LSBjKCJUb3RhbCIsIGNhdGVnb3JpZXMsIHN1YmNhdGVnb3JpZXMsICJPdGhlciIpDQogIA0KICBub2RlX25hbWVzX2RmIDwtIGRhdGEuZnJhbWUoIm5hbWUiID0gbm9kZV9uYW1lcykNCiAgDQogIHRvdGFsX3NhbmtleV90aWJibGUgPC0gdG90YWxfZW1pc3Npb25zX2J5X2NhdCAlPiUNCiAgICBtdXRhdGUodG90YWwgPSAiVG90YWwiKSAlPiUgDQogICAgbXV0YXRlKHRvdGFsID0gbWF0Y2godG90YWwsIG5vZGVfbmFtZXMpIC0xKSAlPiUgDQogICAgbXV0YXRlKGNhdGVnb3J5X25hbWUgPSBtYXRjaChjYXRlZ29yeV9uYW1lLCBub2RlX25hbWVzKSAtMSkgJT4lIA0KICAgIHNlbGVjdChzb3VyY2UgPSB0b3RhbCwNCiAgICAgICAgICAgdGFyZ2V0ID0gY2F0ZWdvcnlfbmFtZSwNCiAgICAgICAgICAgdmFsdWUgPSBjYXRfc3VtKQ0KICANCiAgdG90YWxfZmlsdGVyZWRfZW1pc3Npb25zIDwtIHRvdGFsX3NhbmtleV90aWJibGUgJT4lIA0KICAgIHN1bW1hcmlzZShzdW0odmFsdWUpKSAlPiUgDQogICAgcHVsbCgpDQogIA0KICBvdGhlcl9lbWlzc2lvbnMgPC0gdG90YWxfZW1pc3Npb25zX2Zvcl9nYXMgLSB0b3RhbF9maWx0ZXJlZF9lbWlzc2lvbnMNCiAgDQogIHRvdGFsX290aGVyX3NhbmtleV90aWJibGUgPC0gdGliYmxlKA0KICAgICJzb3VyY2UiID0gYygwKSwNCiAgICAidGFyZ2V0IiA9IChtYXRjaCgiT3RoZXIiLCBub2RlX25hbWVzKSAtMSksDQogICAgInZhbHVlIiA9IGMob3RoZXJfZW1pc3Npb25zKQ0KICApDQogIA0KICBzdWJfc2Fua2V5X3RpYmJsZSA8LSBmaWx0ZXJlZF90aWJibGUgJT4lIA0KICAgIHNlbGVjdCgtY2F0ZWdvcnlfaWQsIC1zdWJjYXRlZ29yeV9pZCwgLXllYXIpICU+JSANCiAgICBtdXRhdGUoY2F0ZWdvcnlfbmFtZSA9IG1hdGNoKGNhdGVnb3J5X25hbWUsIG5vZGVfbmFtZXMpIC0xLA0KICAgICAgICAgICBzdWJjYXRlZ29yeV9uYW1lID0gbWF0Y2goc3ViY2F0ZWdvcnlfbmFtZSwgbm9kZV9uYW1lcykgLTEpDQogIA0KICBuYW1lcyhzdWJfc2Fua2V5X3RpYmJsZSkgPSBjKCJzb3VyY2UiLCAidGFyZ2V0IiwgInZhbHVlIikNCiAgDQogIHNhbmtleV90aWJibGUgPC0gdG90YWxfc2Fua2V5X3RpYmJsZSAlPiUgDQogICAgYmluZF9yb3dzKHN1Yl9zYW5rZXlfdGliYmxlKSAlPiUgDQogICAgYmluZF9yb3dzKHRvdGFsX290aGVyX3NhbmtleV90aWJibGUpDQogIA0KICBsaW5rc19tYXRyaXggPC0gZGF0YS5mcmFtZShhcy5tYXRyaXgoc2Fua2V5X3RpYmJsZSwgYnlyb3cgPSBUUlVFLCBuY29scyA9IDMpKQ0KICANCiAgIyBBZGQgYSAnZ3JvdXAnIGNvbHVtbiB0byBlYWNoIGNvbm5lY3Rpb246DQogIGxpbmtzIDwtIGxpbmtzX21hdHJpeCAlPiUgDQogICAgbXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKA0KICAgICAgc291cmNlID09IDAgfiBwYXN0ZSgidHlwZV8iLCB0YXJnZXQsIHNlcCA9ICIiKSwNCiAgICAgIHNvdXJjZSE9MCB+IHBhc3RlKCJ0eXBlXyIsIHNvdXJjZSwgc2VwID0gIiIpDQogICAgKSkNCiAgDQogIG5vZGVzIDwtIG5vZGVfbmFtZXNfZGYNCiAgIyBBZGQgYSAnZ3JvdXAnIGNvbHVtbiB0byBlYWNoIG5vZGUuDQogICMgQWxsIG9mIHRoZW0gaW4gdGhlIHNhbWUgZ3JvdXAgdG8gbWFrZSB0aGVtIHRoZSBzYW1lIGNvbG91cg0KICBub2RlcyRncm91cCA8LSBhcy5mYWN0b3IoYygibXlfdW5pcXVlX2dyb3VwIikpDQogIA0KICBlbWlzc2lvbnMgPC0gbGlzdCgpDQogIA0KICBlbWlzc2lvbnMkbm9kZXMgPC0gbm9kZXMNCiAgZW1pc3Npb25zJGxpbmtzIDwtIGxpbmtzDQogIA0KICByZXR1cm4oZW1pc3Npb25zKQ0KfQ0KYGBgDQoNCg0KYGBge3J9DQptYWtlX3NhbmtleV9kZnMoZW1pc3Npb25zX3NhbmtleSwgdXNlclllYXIgPSAyMDA1LCB1c2VyR2FzID0gIkNINCIsIHVzZXJSZXNvbHV0aW9uID0gNTApDQpgYGANCmBgYHtyfQ0KDQpgYGANCg0K